PHP preg_match_all并不匹配所有内容

PHP preg_match_all并不匹配所有内容,php,regex,preg-match,preg-match-all,Php,Regex,Preg Match,Preg Match All,考虑以下代码段: $example = "DELIM1test1DELIM2test2DELIM1test3DELIM2test4"; // and so on preg_match_all('/DELIM1(.*?)DELIM2(.*?)/', $example, $matches); $matches数组变为: array:3 [ 0 => array:2 [ 0 => "DELIM1test1DELIM2" 1 => "DELIM1test3DEL

考虑以下代码段:

$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 => ""
  ]
]

如您所见,它无法获取
test2
test4
。为什么会发生这种情况?有什么可能的解决办法?谢谢。

*?
不贪婪;如果后面没有约束,则它将匹配所需的最小值:零个字符。您需要在它之后添加一个约束,以强制它进行匹配。例如:

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

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

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

/DELIM1(.*?)DELIM2(.*?)(?=$|DELIM1)/
看。就性能而言,它与(
DELIM1(.*)DELIM2((?:(?!DELIM1)。*)非常接近。
-)

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

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

参见

预分割会更好:

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

演示:

您可以使用此负前瞻正则表达式:

preg_match_all('/DELIM1((?:(?!DELIM1|DELIM2).)*)DELIM2((?:(?!DELIM1|DELIM2).)*)/',
                $example, $matches);
(?:(?!DELIM1 | DELIM2)。*
将匹配下一位置没有
DELIM1
DELIM2
的任何字符中的0个或多个

输出:

print_r($matches);

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

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

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

这些值不在您的锚定范围内,因此它们不会匹配。e、 g.(带有一些额外的空格)

(.*)
是非贪婪匹配,可以/将匹配0长度的字符串。由于
M2
te
之间的边界是一个0长度的字符串,因此该不可见的零长度字符匹配,模式终止于此

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