Ósc*_*ios 6 php regex router backbone.js
我已经编写了一个PHP控制器,但我正在重写我的代码,所以我可以使用类似Backbone路由器的JSON路由将URI模式映射到PHP Class ::方法组合,或直接转换为HTML文档然后传递给客户端,像这样:
{
"/home" : "index.html",
"/podcasts": "podcasts.html",
"/podcasts/:param1/:param2": "SomeClass::someMethod"
}
Run Code Online (Sandbox Code Playgroud)
Backbone动态创建正则表达式以匹配URL的路由.我查看了主干代码,并提取了以下代码(它有点修改):
function _routeToRegExp (route) {
var optionalParam = /\((.*?)\)/g;
var namedParam = /(\(\?)?:\w+/g;
var splatParam = /\*\w+/g;
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
route = route.replace(escapeRegExp, '\\$&')
.replace(optionalParam, '(?:$1)?')
.replace(namedParam, function(match, optional){
return optional ? match : '([^\/]+)';
})
.replace(splatParam, '(.*?)');
return new RegExp('^' + route + '$');
}
Run Code Online (Sandbox Code Playgroud)
当我通过/podcasts/:param1/:param2上面的代码之类的路线时,我得到了/^\/podcasts\/([^\/]+)\/([^\/]+)$/.我试图编写一个PHP函数来获得完全相同的正则表达式.我试过了:
$route = '/podcasts/:param1/:param2';
$a = preg_replace('/[\-{}\[\]+?.,\\\^$|#\s]/', '\\$&', $route); // escapeRegExp
$b = preg_replace('/\((.*?)\)/', '(?:$1)?', $a); // optionalParam
$c = preg_replace('/(\(\?)?:\w+/', '([^\/]+)', $b); // namedParam
$d = preg_replace('/\*\w+/', '(.*?)', $c); // splatParam
$pattern = "/^{$d}$/";
echo "/^\/podcasts\/([^\/]+)\/([^\/]+)$/\n";
echo "{$pattern}\n";
$matches = array();
preg_match_all($pattern, '/podcasts/param1/param2', $matches);
print_r($matches);
Run Code Online (Sandbox Code Playgroud)
我的输出是:
/^\/podcasts\/([^\/]+)\/([^\/]+)$/ // The expected pattern
/^/podcasts/([^\/]+)/([^\/]+)$/ // echo "{$pattern}\n";
Array // print_r($matches);
(
)
Run Code Online (Sandbox Code Playgroud)
为什么我的正则表达式输出不同?我可以处理映射过程的其余部分,但是我还没有弄清楚如何在PHP中获得与Javascript完全相同的正则表达式.有什么建议?
JS 版本实际上并没有转义 / 字符,它生成与 PHP 版本相同的字符串表示形式 /podcasts/([^/]+)/([^/]+),但是,这可能是让您绊倒的原因, aconsole.log返回的正则表达式 _routeToRegExp显示了带有分隔 / 的完整表示形式,并且内部转义了:
//Firefox output
RegExp /^\/podcasts\/([^\/]+)\/([^\/]+)$/
Run Code Online (Sandbox Code Playgroud)
请参阅http://jsfiddle.net/w6zP2/进行演示。
@ajshort 在评论中指出的和 Backbone 所做的是相同的解决方案:跳过 / 转义并使用替代语法;Backbone 通过显式调用 Regexp 构造函数来完成此操作new RegExp('^' + route + '$'),您可以执行类似的操作$pattern = "~^{$d}$~";
PHP Fiddle http://phpfiddle.org/main/code/4de-jf3似乎按预期工作。
请注意,在 Javascript 中$&,替换字符串会插入匹配的子字符串1 ,而在 PHP 2中则不然。escapeRegExp 应该被修改并且可能看起来像:
$a = preg_replace('/[\-{}\[\]+?.,\\\^$|#~\s]/', '\\\\$0', $route);
Run Code Online (Sandbox Code Playgroud)
这给了我们更新的代码:
$a = preg_replace('/[\-{}\[\]+?.,\\\^$|#~\s]/', '\\\\$0', $route); // escapeRegExp
$b = preg_replace('/\((.*?)\)/', '(?:$1)?', $a); // optionalParam
$c = preg_replace('/(\(\?)?:\w+/', '([^\/]+)', $b); // namedParam
$d = preg_replace('/\*\w+/', '(.*?)', $c); // splatParam
$pattern = "~^{$d}$~";
echo "/^\/podcasts\/([^\/]+)\/([^\/]+)$/\n";
echo "{$pattern}\n";
$matches = array();
preg_match_all($pattern, '/podcasts/param1/param2', $matches);
print_r($matches);
Run Code Online (Sandbox Code Playgroud)
1请参阅在string.replace中指定字符串作为参数2请参阅preg_replace中的替换