PHP preg_match_all 并不匹配所有内容

PHP preg_match_all does not match everything

考虑以下代码片段:

$example = "DELIM1test1DELIM2test2DELIM1test3DELIM2test4"; // and so on

preg_match_all('/DELIM1(.*?)DELIM2(.*?)/', $example, $matches);

$matches 数组变为:

array:3 [
  0 => array:2 [
    0 => "DELIM1test1DELIM2"
    1 => "DELIM1test3DELIM2"
  ]
  1 => array:2 [
    0 => "test1"
    1 => "test3"
  ]
  2 => array:2 [
    0 => ""
    1 => ""
  ]
]

如您所见,它无法获取 test2test4。发生这种情况的任何原因以及可能的解决方案是什么?谢谢。

.*? 是非贪婪的;如果后面没有约束,它将匹配最少的必要字符:零个字符。在它之后你需要一个约束来强制它匹配更多。例如:

/DELIM1(.*?)DELIM2(.*?)(?=DELIM1|$)/

模式末尾的惰性子模式匹配 0 (*?) 或 1 (+?) 个字符,因为它们匹配得尽可能少。

您仍然可以使用惰性匹配并附加一个前瞻性,这将要求 DELIM1 出现在值或字符串结尾之后:

/DELIM1(.*?)DELIM2(.*?)(?=$|DELIM1)/

参见 demo. It is very close in terms of performance with a tempered greedy token (DELIM1(.*?)DELIM2((?:(?!DELIM1).)*) - demo)。

但是,最好的方法是展开它:

DELIM1(.*?)DELIM2([^D]*(?:D(?!ELIM1)[^D]*)*)

another demo

preg_split会更好:

$example = "DELIM1test1DELIM2test2DELIM1test3DELIM2test4"; // and so on
$keywords = preg_split("/DELIM1|DELIM2/", $example,0,PREG_SPLIT_NO_EMPTY);
print_r($keywords);

输出:

Array
(
    [0] => test1
    [1] => test2
    [2] => test3
    [3] => test4
)

演示:http://ideone.com/s5nC0k

您可以使用这个否定的先行正则表达式:

preg_match_all('/DELIM1((?:(?!DELIM1|DELIM2).)*)DELIM2((?:(?!DELIM1|DELIM2).)*)/',
                $example, $matches);

(?:(?!DELIM1|DELIM2).)* 将匹配 0 个或多个在下一个位置没有 DELIM1DELIM2 的任何字符。

输出:

print_r($matches);

    Array
    (
        [0] => Array
            (
                [0] => DELIM1test1DELIM2test2
                [1] => DELIM1test3DELIM2test4
            )

        [1] => Array
            (
                [0] => test1
                [1] => test3
            )

        [2] => Array
            (
                [0] => test2
                [1] => test4
            )        
    )

这些值在您的锚点之外,因此无法匹配。例如(有一些额外的空格)

str:  DELIM1  test1  DELIM2         test2   DELIM1  test3  DELIM2        test4
pat:  DELIM1  (.*?)  DELIM2  (.*?)          DELIM1  (.*?)  DELIM2 (.*?) 
             match #1                                match #2

(.*?)是非贪婪匹配,can/will匹配一个0长度的字符串。由于 M2te 之间的边界是一个长度为 0 的字符串,因此该不可见的零长度字符匹配并且模式在那里终止。