6

皆さん!正規表現などについて助けが必要です。アプリケーション内のある種のルーターであるURLから仮想キーを抽出する必要があります。パラメータは次のとおりです。

Rule: /books/:category/:id/:keyname
Data: /books/php/12345/this-is-a-test-keyname

出力は次のようになります。

array(
  'category' => 'php',
  'id' => '12345',
  'keyname' => 'this-is-a-test-keyname'
);

問題は、php でこれを行うにはどうすればよいかということです。

PS ルールの組み合わせはさまざまです。したがって、主なキーは「:」記号の付いた単語です。たとえば、次のようにします。

/book-:id/:category/:keyname
/book/:id_:category~:keyname

PS 2: これは私が以前持っていたコードです。機能していますが、柔軟ではありません。

function rule_process($rule, $data) {
        // extract chunks       
        $ruleItems = explode('/',$rule);
        $dataItems = explode('/',$data);

        // remove empty items
        array_clean(&$ruleItems);
        array_clean(&$dataItems);

        // rule and data supposed to have the same structure
        if (count($ruleItems) == count($dataItems)) {
            $result = array();

            foreach($ruleItems as $ruleKey => $ruleValue) {
                // check if the chunk is a key
                if (preg_match('/^:[\w]{1,}$/',$ruleValue)) {
                    // ok, found key, adding data to result
                    $ruleValue = substr($ruleValue,1);
                    $result[$ruleValue] = $dataItems[$ruleKey];
                }
            }

            if (count($result) > 0) return $result;
            unset($result);
        }

        return false;
    }

    function array_clean($array) {
        foreach($array as $key => $value) {
            if (strlen($value) == 0) unset($array[$key]);
        }   
    }

実際、このバージョンのルーターで十分な場合がありますが、柔軟なソリューションを作成する方法に興味があります。ちなみに、いくつかのテスト: (10000 操作の 30 回):

TEST #0 => Time:0.689285993576, Failures: 0
TEST #1 => Time:0.684408903122, Failures: 0
TEST #2 => Time:0.683394908905, Failures: 0
TEST #3 => Time:0.68522810936, Failures: 0
TEST #4 => Time:0.681587934494, Failures: 0
TEST #5 => Time:0.681943893433, Failures: 0
TEST #6 => Time:0.683794975281, Failures: 0
TEST #7 => Time:0.683885097504, Failures: 0
TEST #8 => Time:0.684013843536, Failures: 0
TEST #9 => Time:0.684071063995, Failures: 0
TEST #10 => Time:0.685361146927, Failures: 0
TEST #11 => Time:0.68728518486, Failures: 0
TEST #12 => Time:0.688632011414, Failures: 0
TEST #13 => Time:0.688556909561, Failures: 0
TEST #14 => Time:0.688539981842, Failures: 0
TEST #15 => Time:0.689876079559, Failures: 0
TEST #16 => Time:0.689854860306, Failures: 0
TEST #17 => Time:0.68727684021, Failures: 0
TEST #18 => Time:0.686210155487, Failures: 0
TEST #19 => Time:0.687953948975, Failures: 0
TEST #20 => Time:0.687957048416, Failures: 0
TEST #21 => Time:0.686664819717, Failures: 0
TEST #22 => Time:0.686244010925, Failures: 0
TEST #23 => Time:0.686643123627, Failures: 0
TEST #24 => Time:0.685017108917, Failures: 0
TEST #25 => Time:0.686363935471, Failures: 0
TEST #26 => Time:0.687278985977, Failures: 0
TEST #27 => Time:0.688650846481, Failures: 0
TEST #28 => Time:0.688835144043, Failures: 0
TEST #29 => Time:0.68886089325, Failures: 0

それで、十分に速いです。通常のラップトップでテストしています。確かに、これは実際の Web サイトで使用できます。

他の解決策はありますか?

4

5 に答える 5

1

別のバージョンのスクリプトがあります: http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/

于 2009-09-26T19:22:00.250 に答える
1

1 つの正規表現だけでは、これは不可能だと思います。Zend Framework は、あなたの例と同じように機能します。ソースコードを見てください。

于 2009-07-02T10:27:23.457 に答える
1

この簡単な解決策を試してください:

    $data = Array (
            "/book/:id/:category/:keyname" => "/book/12345/php/this-is-a-test-keyname",
            "/book-:id/:category/:keyname" => "/book-12345/php/this-is-a-test-keyname",
            "/book/:id_:category~:keyname" => "/book/12345_php~this-is-a-test-keyname",
    );


    foreach ($data as $rule => $uri) {
            $reRule = preg_replace('/:([a-z]+)/', '(?P<\1>[^/]+)', $rule);
            $reRule = str_replace('/', '\/', $reRule);

            preg_match('/' . $reRule .'/', $uri, $matches);
            print_r($matches);
    }

唯一の欠点は、現時点では高度なデータ検証を行うことができないため、別の場所で行う必要があることです。また、ルールが正規表現の構文と競合する場合は、面倒になる可能性があります (ここで重いエスケープ作業を行う必要があります)。

于 2009-07-02T10:54:35.867 に答える
0

要素ごとにいくつかのパターンを定義することから始めます

$element=array(
    'id'=>'(\d+)',
    'category'=>'([^/]+)'
);

次に、正規表現を作成します

$rule="/book-:id/:category/:keyname";

$pattern=preg_quote($rule);
$map=array();
$map[]=null;

function initrule($matches) 
{
    //forgive the globals - quickest way to demonstrate this, in
    //production code I'd wrap this into a class...
    global $element;
    global $map;

    //remember the order we did these replacements
    $map[]=$matches[1];

    //return the desired pattern
    return $element[$matches[1]];
}

$pattern=preg_replace_callback('/:(\w+)/', "initrule", $pattern);

ターゲットデータでそのパターンを使用できることに注意してください。返される一致の配列は、$map配列の要素名に対応している必要があります。たとえば名前$match[1]は$map[1]にあります。

于 2009-07-02T10:27:46.217 に答える
0
$Url = preg_replace("/^(.*)\\/\\/\/|(.*)\\/*.php\//i", "", $_SERVER['REQUEST_URI']);
$Url = str_replace("index.php", "", $Url);
$data = array();

$data["/ttt/:xyz/:id"]  =(object) Array (   "default"   =>  array("controller"=>"default","action"=>"detail"),
                                                    "rule"      =>  array("xyz"=>"([a-zA-Z0-9_\+\-%]+)","id"=>"([0-9]+)"));
$data["/xid-:id"]   =(object) Array (   "default"   =>  array("controller"=>"default","action"=>"categori"),
                                    "rule"      =>  array("id"=>"([a-z]+)"));

function parsePath($match) 
{
    global $data;
    foreach($data as $router)
    {
        foreach($router->rule as $key=>$value)
        {
            if($match[1] == $key){
                $str ='(?P<'.$match[1].'>'.$value.')';
            } else {
                $str = '(?P<'.$match[1].'>[^/]+)';
            }
        }
    }

    return $str;

}

foreach($data as $path => $router)
{
    $o=preg_replace_callback('/:([a-z]+)/',"parsePath", $path);
}

$regex = str_replace('/', '\/',$o);
$regex ='/^' . $regex . '$/';

preg_match($regex, $Url, $matches);
$map = array();

foreach($matches as $key => $value)
{
    foreach($data as $route)
    {
        if(array_key_exists($key,$route->rule)){
            $map['controller'] = $route->default['controller']; 
            $map['action']= $route->default['action'];  
            $map[$key] = $value;
        }
    }
}
于 2011-06-25T07:57:22.933 に答える