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

正如@nickb 已经评论的那样,重复捕获组仅保留其最后一场比赛。AFAIK,只有 .NET 提供了保留所有匹配项的实现。所以,我同意@m.buettner 的观点,即您必须至少使用两个匹配项。而@IngmardeLange 的解决方案似乎是一种替代实现,虽然我没有检查过,但仍然使用至少两个匹配项。

为了好玩,我设计了一种使用单个匹配的方法。最初的想法是对@{article部件使用lookbehinds,但不支持可变长度lookbehinds。然后,(不幸的是,正如您将要见证的那样)我记得@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
                )
        )
)

这是一个正在运行的示例。

很明显,如果我还没有充分否认这一点,那么所有的逆转成本都不仅仅是做两场比赛。但是也许有一个应用程序可以将具有可变长度后视的表达式一般转换为如上所述的反向前瞻,然后返回。虽然可能不是。

于 2012-12-20T16:50:08.210 回答
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 回答