正则表达式匹配两个百分号之间的字符串

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%

我错过了什么?

7个回答

13

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

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

现在发生的情况是"."会贪婪地匹配尽可能多的内容,包括行尾的百分号。将其替换为否定字符类"[^%]"意味着它将匹配除了百分号以外的任何字符,这将使它只匹配您想要的部分。

另一个选项是在点号后面加上"?",告诉它"不要贪婪匹配":

preg_match_all("/%.*?%/", "%hey%_thereyou're_a%rockstar%\nyo%there%", $matches);
在上面的示例中,任一选项都可以工作,但有时您可能正在搜索比单个字符更大的内容,因此否定字符类将无法帮助,因此解决方案是使匹配变得不贪婪。

4
您正在使用贪婪匹配 - 使用?使其无限制:
/%.*?%/

如果匹配项中包含换行符,请添加 s(DOTALL)修饰符:
/%.*?%/s

2
在 * 后面添加一个 ? :
preg_match_all("/%.*?%/", "%hey%_thereyou're_a%rockstar%\nyo%there%", $matches);

1

|%(\w+)%| 这将完美地实现你想要的功能。


1
原因是星号太贪心了。也就是说,星号会导致正则表达式引擎尽可能多地重复前面的标记。你应该尝试使用.*?代替。

1
你可以尝试使用/%[^%]+%/,这意味着在百分号之间,你只想匹配不是百分号的字符。
你也可以尝试将模式设置为非贪婪模式,例如/%.+%/U,这样它会尽可能地捕获最少的内容(我认为是这样)。

更准确地说,/U 反转正则表达式中所有量词的贪婪性,因此 /%.+%/U/%.+?%/ 相同,而 /%.+?%/U/%.+%/ 相同。http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php - Alan Moore

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) 和百分号 (%) 之外的任意零个或多个字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接