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 => ""
]
]
如您所见,它无法获取 test2
和 test4
。发生这种情况的任何原因以及可能的解决方案是什么?谢谢。
.*?
是非贪婪的;如果后面没有约束,它将匹配最少的必要字符:零个字符。在它之后你需要一个约束来强制它匹配更多。例如:
/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]*)*)
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
)
您可以使用这个否定的先行正则表达式:
preg_match_all('/DELIM1((?:(?!DELIM1|DELIM2).)*)DELIM2((?:(?!DELIM1|DELIM2).)*)/',
$example, $matches);
(?:(?!DELIM1|DELIM2).)*
将匹配 0 个或多个在下一个位置没有 DELIM1
或 DELIM2
的任何字符。
输出:
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长度的字符串。由于 M2
和 te
之间的边界是一个长度为 0 的字符串,因此该不可见的零长度字符匹配并且模式在那里终止。
考虑以下代码片段:
$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)/
参见 demo. It is very close in terms of performance with a tempered greedy token (DELIM1(.*?)DELIM2((?:(?!DELIM1).)*)
- demo)。
但是,最好的方法是展开它:
DELIM1(.*?)DELIM2([^D]*(?:D(?!ELIM1)[^D]*)*)
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
)
您可以使用这个否定的先行正则表达式:
preg_match_all('/DELIM1((?:(?!DELIM1|DELIM2).)*)DELIM2((?:(?!DELIM1|DELIM2).)*)/',
$example, $matches);
(?:(?!DELIM1|DELIM2).)*
将匹配 0 个或多个在下一个位置没有 DELIM1
或 DELIM2
的任何字符。
输出:
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长度的字符串。由于 M2
和 te
之间的边界是一个长度为 0 的字符串,因此该不可见的零长度字符匹配并且模式在那里终止。