2013-01-31 10 views
6

私はすでにPHPコントローラを作成していますが、URIパターンをPHPクラス::メソッドの組み合わせにマップするBackbone Router風のJSONルートを作成できるように、PHPの動的正規表現を使用したバックボーン型ルータ

{ 
    "/home" : "index.html", 
    "/podcasts": "podcasts.html", 
    "/podcasts/:param1/:param2": "SomeClass::someMethod" 
} 

バックボーンはURLとルートを照合するための正規表現を動的に作成します。私は/^\/podcasts\/([^\/]+)\/([^\/]+)$/を取得し、私は上記のコードに、/podcasts/:param1/:param2のようなルートを渡す場合

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 + '$'); 
} 

:私は、バックボーン・コードに見ていた、と私は、次のコードを(それはビットが変更されています)を抽出しました。私は正確に同じ正規表現を取得する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); 

私の出力は次のとおりです。

/^\/podcasts\/([^\/]+)\/([^\/]+)$/ // The expected pattern 
/^/podcasts/([^\/]+)/([^\/]+)$/  // echo "{$pattern}\n"; 
Array         // print_r($matches); 
(
) 

なぜ私の正規表現の出力が違うのですか?私は残りのすべてのマッピング処理を扱うことができますが、JavascriptのようにPHPで正確に同じ正規表現を取得する方法はわかりません。助言がありますか?

+0

これはあまりにもイライラしているので、同僚はCLIを使ってその正規表現を返す非常に便利なnodeJs関数を書いてくれました。 PHPでこれを行う方法が見つかったら、私は確かに正しい答えを投稿します。 :) –

+1

簡単な修正:正規表現の区切りには〜を使用します。つまり、/ pattern /ではなく〜pattern〜です。そうすれば、/文字をエスケープする必要はありません。これは正規表現を少し読みやすくします。 – ajshort

答えて

2

JSのバージョンは、実際には/の文字をエスケープしていない、それはあなたのPHPのバージョン/podcasts/([^/]+)/([^/]+)と同じ文字列表現を生成するが、それはあなたを倒してしまった。おそらく何だ、_routeToRegExpによって返された正規表現のconsole.logはとの完全な表現を示します内側のものはエスケープされます:

//Firefox output 
RegExp /^\/podcasts\/([^\/]+)\/([^\/]+)$/ 

デモ用にはhttp://jsfiddle.net/w6zP2/を参照してください。

@ajshortがコメントに記したものと、Backboneと同じ解決策は何ですか?/エスケープをスキップし、別の構文を使用します。バックボーンはnew RegExp('^' + route + '$')と正規表現のコンストラクタを明示的に呼び出してそれをしない、あなたは$pattern = "~^{$d}$~";

そして期待通りに動作しているようですPHPフィドルhttp://phpfiddle.org/main/code/4de-jf3と似た何かを行うことができます。

注Javascriptの$&で置換文字列にそれはないPHP にので、マッチした部分文字列を挿入します。 escapeRegExpは修正されなければならないと次のようになります。

$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); 

string.replace
にパラメータとして文字列を指定を参照してください。私たちに更新されたコードを与える

$a = preg_replace('/[\-{}\[\]+?.,\\\^$|#~\s]/', '\\\\$0', $route); 

交換preg_replace

+0

phpfiddleの例を試してみましたが、それは完璧に機能しました!ありがとう@nikoshr。私は、コードについて作業し、さらにいくつかのテストとすべてを済ませたらすぐにどこかで完全なサンプルを投稿します。とにかくそのnodeJs関数を使って作業するのは厄介でした! :D –

+0

@オスカルPalacios喜んでそれは助け:) – nikoshr