4

この種のコードを解析したいと思います:

{articles mode="extrait" nb="3"}

私はこの正規表現を使用しています:

@\{(articles)(?:(?:\s|\ )*(?:(\w+)="(\w+)"))*\}@

preg_match_all を実行すると、 $matches パラメータを使用した print_r の結果が次のようになります。

Array (
    [0] => {articles mode="extraits" nb="3"}
    [1] => articles
    [2] => nb
    [3] => 3
)

最後の * は、最後の属性だけでなく、すべての属性を取得するトリックを実行する必要があると考えました。

不足しているものや間違っているものはありますか?

前もって感謝します

4

3 に答える 3

0

@nickb が既にコメントしたように、繰り返されるキャプチャ グループは最後の一致のみを保持します。私の知る限り、すべての一致を保持する実装を提供するのは.NETだけです。したがって、少なくとも 2 つの一致を使用する必要があるという @m.buettner に同意します。また、@ IngmardeLangeのソリューションは代替実装のようですが、チェックしていませんが、少なくとも2つの一致を使用しています.

楽しみのために、1 つのマッチを使用してこれを行う方法を考案しました。最初のアイデアは、@{article部分に後読みを使用することでしたが、可変長の後読みはサポートされていません。次に、(残念ながら、あなたが目撃しようとしているように)@TimPietzckerが可変長の後読みを実装するためのトリックについて言及したことを思い出しました:逆の文字列で可変長の先読みを行います。(実際にこのメソッドを使用しないでください。)

<?php

    function get_attr_val_matches($tag, $subject)
    {
        $regex = '/"(\w+)"=(\w+)\s+(?=(?:"\w+"=\w+\s+)*' . strrev($tag) . '\{@)/';
        preg_match_all($regex, strrev($subject), $matches, PREG_SET_ORDER);

        foreach ($matches as &$match)
        {
            $match = array_map(strrev, $match);
            $match = array($match[0], array_reverse(array_slice($match, 1)));
        }

        return array_reverse($matches);
    }

    $tag = 'articles';
    $subject = '@{articles mode="extrait" nb="3"}';

    print_r(get_attr_val_matches($tag, $subject));

?>

出力:

Array
(
    [0] => Array
        (
            [0] =>  mode="extrait"
            [1] => Array
                (
                    [0] => mode
                    [1] => extrait
                )
        )

    [1] => Array
        (
            [0] =>  nb="3"
            [1] => Array
                (
                    [0] => nb
                    [1] => 3
                )
        )
)

実行例を次に示します。

明らかに、これについてまだ十分に断言していない場合、すべての逆転には、2 つのマッチを実行するよりも多くのコストがかかります。しかし、おそらく、可変長の後読みを持つ式を一般的に変換し、上記のように逆先読みに変換してから戻すアプリケーションがあります。おそらくそうではありませんが。

于 2012-12-20T16:50:08.210 に答える
0
$instances = array();

@ preg_match_all( '/\{articles([^\}]+)\}/', $string, $articles );

if ( false === empty( $articles[1][0] ))
{
   foreach ( $articles[1] as $article )
   {
      @ preg_match_all( '/\b(\w+)="([^"]+)"/', $article, $arguments );

      if ( false === empty( $arguments[0][0] ))
      {
         $settings = array();

         foreach ( $arguments[0] as $index => $argument )
         {
            $settings[$arguments[1][$index]] = $arguments[2][$index];
         }

         $instances[] = $settings;
      }

      unset( $arguments );
   }
}

print_r( $instances );
于 2012-12-20T16:36:43.120 に答える
0

わからないことばかりだったのに、ご回答ありがとうございます。

はるかに簡単ですが、引数が2つだけに制限されている別の方法を見つけました(今のところそれ以上は必要ありません):

@\{(articles)((\s)(\w+)="(\w+)")?((\s)(\w+)="(\w+)")?\}@

Array 
( 
[0] => {articles nb="2" mode="extrait"} 
[1] => articles 
[2] => nb="2" 
[3] => 
[4] => nb 
[5] => 2 
[6] => mode="extrait" 
[7] => 
[8] => mode 
[9] => extrait 
)

そして、私は次のようなことをします:

if($key = array_search('mode', $option)) $mode = $option[$key + 1];

if($mode == 'extrait')
{
    // my stuff here
}

繰り返しますが、すべての回答に感謝します!

于 2012-12-20T17:20:59.773 に答える