Reputation: 10765
I'm looking at building a super simple router in javaScript...so far I have this:
var match,routeMatcher,p;
var routes = {
"/users/:uid/pictures/:uid" : "userpictures",
"/users/:uid" : "user"
};
var url = "/users/1024/pictures/456";
for(var i in routes) {
//need to cache this regex
routeMatcher = new RegExp(i.replace(/:[^\s/]+/g, '([\\w-]+)'));
if(url.match(routeMatcher)) {
match = url.match(routeMatcher);
p = routes[i];
console.log(p);
}
}
and here's a fiddle http://jsfiddle.net/D6txe/
This works. When I feed in a url like "users/1000" I get back the corresponding function name (just got to work out how to call the string as a function now). Problem is if I have two routes that are very similar as in my example the regex matches both. In the example above I'd ideally only like the second route to be matched but unfortunately both get matched, because of course the first is also a match.
Is there any way I can make the regex only return exact matches? I have another solution which would involve counting the forward slashes in the input url and only call routes with a matching number of forward slashes....but this seems rather inelegant.
Upvotes: 2
Views: 259
Reputation: 338316
Here's a variant that caches your regular expressions (note the '^'
and '$'
in the regex):
function Router(routes) {
var route, routeExp, matchers = {};
for (route in routes) {
if (routes.hasOwnProperty(route)) {
routeExp = '^' + route.replace(/:[^\s/]+/g, '([\\w-]+)') + '$';
matchers[route] = new RegExp(routeExp);
}
}
return function(url) {
var match;
for (route in matchers) {
if (matchers.hasOwnProperty(route)) {
if (match = url.match(matchers[route])) {
return {
route: route,
name: routes[route],
match: match.slice(1)
};
}
}
}
}
}
usage:
var router = new Router({
"/users/:uid/pictures/:uid" : "userpictures",
"/users/:uid" : "user"
});
var result = router("/users/1024/pictures/456");
console.log(result);
/*
{
route: "/users/:uid/pictures/:uid",
name: "userpictures"
match: ["1024", "456"]
}
*/
Upvotes: 2
Reputation: 56819
I am not totally sure whether this is what you need.
I use ^
and $
to make the regex matches the exact format of the path portion of the URL:
routeMatcher = new RegExp("^" + i.replace(/:[^\s\/]+/g, '([\\w-]+)') + "$");
If you are taking the path from window.location.pathname
to do the matching, then it is probably OK.
Upvotes: 2
Reputation: 40478
Try this:
routeMatcher = new RegExp(i.replace(/:[^\s/]+/g, '([\\w-]+)') + "$");
If you also want to support a trailing /
to also cover /users/1024/pictures/456/
, you can change your RegExp as follows:
routeMatcher = new RegExp(i.replace(/:[^\s/]+/g, '([\\w-]+)') + "/?$");
Upvotes: 4