1

I'm doing kind of a reverse templating thing, I have a string, and I know the template used to generate it, I want to get the variable value.

For example: URL: http://c.tile.osm.org/24/7881145/7385476.png

Template: http://{s}.tile.osm.org/{z}/{x}/{y}.png

I would like to get the zoom level ({z}) from the tile's URL, in this case 24. This exact Template url will not always be used (it varies based on what basemap is used, etc.), but I'll always be looking for the {z} value.

cscott530
  • 1,658
  • 16
  • 25

3 Answers3

1

You can capture values using a regex. This thread is similar to your case, and here would be your solution:

var myString = "http://c.tile.osm.org/24/7881145/7385476.png";
var myRegexp = /http:\/\/[A-z]\.tile\.osm\.org\/([0-9]+)\/([0-9]+)\/([0-9]+)\.png/;
var match = myRegexp.exec(myString);
alert(match[1]);  // 24

And here's the fiddle: http://jsfiddle.net/2sx4t/

EDIT:

Following to your comment, here's the most flexible code I could quickly provide you: http://jsfiddle.net/2sx4t/4/

var myString = "http://c.tile.osm.org/24/7881145/7385476.png";
var myTemplate = "http://{s}.tile.osm.org/{z}/{y}/{x}.png";

var myString2 = "//tiles.arcgis.com/tiles/c/arcgis/rest/services/TimeZones/MapServer/tile/223774/24/2636";
var myTemplate2 = "//tiles.arcgis.com/tiles/{s}/arcgis/rest/services/TimeZones/MapServer/tile/{x}/‌{z}/{y}";

var z = extractToken(myTemplate, myString, '{z}');
alert(z);  // 24

var z2 = extractToken(myTemplate, myString, '{z}');
alert(z2); // 24

The tricks in this code is the combination of the use of template.indexOf(m) to be able to find the order of your tokens and String.replace() to generate the appropriate RegExp.

Note that I shuffled the order of the tokens in myTemplate2and that it sill works.

Don't expect magic from RegExp, magic is in our brains ;-)

Bonus with map return, independantly of other tokens: http://jsfiddle.net/2sx4t/8/

Community
  • 1
  • 1
ngasull
  • 4,206
  • 1
  • 22
  • 36
  • So I'd have to convert the template first to a regex, then find what index of its groups `{z}` was, and then match it against the tile's URL. Was hoping for something a little simpler but I guess regexes aren't as magical as I hoped :) – cscott530 Apr 16 '14 at 13:46
  • 1
    Oh I didn't exactly get your problem, I'm finding you something else ;) – ngasull Apr 16 '14 at 13:49
  • Phenomenal answer. Worked perfectly. Only other question, as you seem to have your head wrapped around it so well, what if there are unknown params? For instance, I don't know what all types of string replacing Leaflet supports, so there might be additional `{}`-escaped vars in the URL template at some point. – cscott530 Apr 16 '14 at 14:55
  • Thanks! If I understand you're question well, you're wondering if there are other params that could trouble `{z}` fetching. But the previous piece of code can handle any number of tokens. The only requirement is to manually define `tokenMapping` variable. Note that you can pass it throught method's arguments. We were talking about brains, but JS can't read into yours yet! – ngasull Apr 16 '14 at 15:00
  • Yeah, that's correct, I was just hoping to not have to be aware of future tokens. Looks like Grinn's answer below resolved it. Thanks though! – cscott530 Apr 16 '14 at 15:01
  • I based my code on "one token fetching". It can easily be adapted in order to return a map of values (maybe from a map of values (`tokenMapping`..?!) given as parameter) – ngasull Apr 16 '14 at 15:03
  • 1
    Here would have been your final bonus code, handling everything... http://jsfiddle.net/2sx4t/6/ – ngasull Apr 16 '14 at 15:15
1

It looks like blint may have beat me to it, but essentially what you want to do is generate a regular expression from your template and execute it:

function zFromTemplate(str, template) {      
  var sr = template.replace("?", "\\?")
    .replace(/\{[^z]\}/g, ".*?")
    .replace(/\{z\}/g, "(.+)");

  var rex = new RegExp(sr),
      parts = rex.exec(str);

  if(parts) {
    return parts[1];
  }
  return null;
}

And here's a codepen demonstrating it's use. If nothing else it's a little more succinct than the originally accepted answer.

Grinn
  • 5,370
  • 38
  • 51
  • Even handles unforeseen future tokens perfectly. This is exactly what I was hoping for. – cscott530 Apr 16 '14 at 15:03
  • 2
    Just be aware that it works only with a 1 character-long (z) token and that it handles only this token. – ngasull Apr 16 '14 at 15:22
  • One more comment, would recommend changing to: `var sr = template.replace('?', '\\?').replace(/\{[^z]\}/g, ".*?");` just ran into an issue where I had to add a query param to my template URL and it blew up on me! – cscott530 Apr 16 '14 at 18:33
  • @cscott530, good find. I also updated it to chain all of the replace calls. – Grinn Apr 16 '14 at 19:02
0

Well, if you're sure that the {z} parameter is the only 1 or 2 digits element in your URL, you can try with regexp:

var myRegexp = /.*\/([0-9]{1,2})\/.*/;

This would match the last occurrence of any one or two digits enclosed in two slashes (/1/, /24/, ...)

keko81
  • 36
  • 2
  • Not a certainty, either. Could have other numbers hard-coded into the path, or could potentially have either x or y be <= 2 digits. – cscott530 Apr 16 '14 at 14:36