preg_match()可以捕获未知数量的事件吗?

时间:2017-09-30 14:03:42

标签: php regex preg-match

假设我有以下字符串:

[

我需要捕获以下字符串:

  1. printf
  2. $string = 'cats[Garfield,Tom,Azrael]';
  3. cats
  4. Garfield
  5. 该字符串可以是任何类似文字的文本,后面是括号,其中包含逗号分隔的类似字的条目列表。我尝试了以下方法:

    Tom

    问题是Azrael忽略preg_match('#^(\w+)\[(\w+)(?:,(\w+))*\]$#', $string, $matches); ,只匹配第一只猫和最后一只猫。

    现在,我知道如何通过更多调用来实现这一点,可能会将$matchesTom结合起来,所以问题是一般如何做。

    问题是:可以用单preg_match()来完成,所以我可以一次验证和匹配吗?

2 个答案:

答案 0 :(得分:2)

基本问题似乎是:是否可以提取重复捕获组的每次出现?

答案是否定的。

但是,存在几种解决方法:

最容易理解的是使用两个步骤:捕获完整列表然后拆分它。类似的东西:

$str = 'cats[Garfield,Tom,Azrael,Supermatou]';
if ( preg_match('~(?<item>\w+)\[(?<list>\w+(?:,\w+)*)]~', $str, $m) )
    $result = [ $m['item'], explode(',', $m['list']) ];

(或您想要的任何结构)

其他解决方法将preg_match_all\G锚点结合使用,该锚点匹配字符串的开头或成功匹配后的位置:

$pattern = '~(?:\G(?!\A),|(?<item>\w+)\[(?=[\w,]+]))(?<elt>\w+)~';
if ( preg_match_all($pattern, $str, $matches) )
    print_r($matches);

此设计确保所有元素都在括号之间。

要获得更多 flat 结果,您还可以这样写:

$pattern = '~\G(?!\A)[[,]\K\w+|\w+(?=\[[\w,]+])~';

最后一个模式的细节:

~
# first alternative (can't be the first match)
\G (?!\A) # position after the last successful match
          # (the negative lookahead discards the start of the string)
[[,]      # an opening bracket or a comma
\K        # return the whole match from this position
\w+       # an element

|         # OR

# second alternative (the first match)
\w+       # the item
(?=       # lookahead to check forward if the format is correct
    \[        # opening bracket
    [\w,]+    # word characters and comma (feel free to be more descriptive
              # like \w+(?:,\w+)* or anything you want)
    ]         # closing bracket
)
~

答案 1 :(得分:0)

为什么不是简单的preg_match_all:

$string = 'cats[Garfield,Tom,Azrael], entity1[child11,child12,child13], entity2:child21&child22&child23';
preg_match_all('#\w+#', $string, $matches);
print_r($matches);

<强>输出:

Array
(
    [0] => Array
        (
            [0] => cats
            [1] => Garfield
            [2] => Tom
            [3] => Azrael
            [4] => entity1
            [5] => child11
            [6] => child12
            [7] => child13
            [8] => entity2
            [9] => child21
            [10] => child22
            [11] => child23
        )

)