3

我正在尝试匹配包含在 % 中但preg_match_all似乎在同一行中同时包含多个子字符串。

代码如下所示:

preg_match_all("/%.*%/", "%hey%_thereyou're_a%rockstar%\nyo%there%", $matches);
print_r($matches);

这会产生以下输出。

Array
(
    [0] => Array
        (
            [0] => %hey%_thereyou're_a%rockstar%
            [1] => %there%
        )

)

但是我希望它生成以下数组:

[0] => %hey%
[1] => %rockstar%
[2] => %there%

我错过了什么?

4

7 回答 7

12

.将正则表达式中的“”替换为“ [^%]”:

preg_match_all("/%[^%]*%/", "%hey%_thereyou're_a%rockstar%\nyo%there%", $matches);

正在发生的事情是“ .”尽可能地“贪婪地”匹配,包括直到最后 % 的所有内容。用否定字符类“ [^%]”替换它意味着它将匹配百分比之外的任何内容,这将使其仅匹配您想要的位。

另一种选择是?在点之后放置一个“”,告诉它“不要贪婪”:

preg_match_all("/%.*?%/", "%hey%_thereyou're_a%rockstar%\nyo%there%", $matches);

在上面的示例中,任何一个选项都可以,但是有时您可能会搜索大于单个字符的内容,因此否定字符类将无济于事,因此解决方案是取消匹配匹配。

于 2009-08-13T08:06:28.660 回答
4

你正在做一个贪婪的比赛 -?用来让它变得不贪婪:

/%.*?%/

如果匹配中可以出现换行符,请添加 s (DOTALL) 修饰符:

/%.*?%/s
于 2009-08-13T08:07:26.273 回答
2

添加一个?之后 *:

preg_match_all("/%.*?%/", "%hey%_thereyou're_a%rockstar%\nyo%there%", $matches);
于 2009-08-13T08:09:53.960 回答
1

原因是星星很贪心。也就是说,星号使正则表达式引擎尽可能频繁地重复前面的标记。你应该试试 。*?反而。

于 2009-08-13T08:07:51.640 回答
1

您可以尝试/%[^%]+%/- 这意味着在百分号之间您只想匹配不是百分号的字符。

您也可以使模式变得不贪心,例如/%.+%/U,因此它会尽可能少地捕获(我认为)。

于 2009-08-13T08:07:53.043 回答
1

|%(\w+)%| 这将完全符合您的要求。

于 2009-08-19T10:51:04.887 回答
0

虽然解决方案是将贪婪.*变成懒惰.*?(或替换.*[^%]*),但您可能还想真正摆脱%输出中的符号。

在这种情况下,您将需要使用捕获组并获取$matches[1]是否发生匹配:

$str = "%hey%_thereyou're_a%rockstar%\nyo%there%";
if (preg_match_all("/%([^%]*)%/", $str, $matches)) {
    print_r($matches[1]);
}
// => Array( [0] => hey [1] => rockstar [2] => there )

请注意,print_r($matches[0]);将输出完整匹配,// => Array( [0] => %hey% [1] => %rockstar% [2] => %there% ). 该[^%]模式是一个否定字符类,它匹配除字符之外的任何%字符。

请参阅PHP 演示

变化

如果您需要确保%字符之间只有字母、数字或下划线,您可以使用

"/%(\w*)%/"

如果要匹配%两个字符之间的空格以外的任何字符,请%使用

"/%([^\s%]*)%/"

[^\s%]*模式是一个正则表达式,它匹配除空格 ( \s) 和一个字符之外的任何零个或多个字符%

于 2022-01-24T11:21:05.223 回答