奇怪的 PHP 正则表达式 Preg_Match 错误?

Weird PHP Regex Preg_Match Bug?

我的 PHP 版本是 PHP 7.2.24-0ubuntu0.18.04.7 (cli)。但是,我测试过的所有版本似乎都会出现此问题。

我在使用 preg_match 时遇到了一个非常奇怪的错误。有人知道解决方法吗?

此处代码的第一部分有效,第二部分无效。但是正则表达式本身是有效的。出于某种原因,something_happened 字导致它失败。

$one = ' (branch|leaf)';
echo "ONE:\n";
preg_match('/(?:\( ?)?((?:(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+(?: ?\| ?(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+)(?: ?\))?/', $one, $matches, PREG_OFFSET_CAPTURE);
print_r($matches); // this works

$two = 'something_happened (branch|leaf)';
echo "\nTWO:\n";
preg_match('/(?:\( ?)?((?:(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+(?: ?\| ?(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+)(?: ?\))?/', $two, $matches2, PREG_OFFSET_CAPTURE);
print_r($matches2); // this doesn't work

似乎与something_happened这个词有些关联。如果我改变这个词,它就会起作用。

正则表达式匹配 2 个或多个由 | 分隔的类型名称,这些名称可能包含也可能不包含在 () 中,并且每个类型名称前面可能有也可能没有任意数量的 [](或[some number][!some number])和*.

试试看吧!如果您知道如何修复它,请告诉我!

问题出在 (?:(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+ 组:+ 量词量化了具有许多后续可选模式的组,并且创建了太多选项以匹配后续模式之前的字符串。

在 PHP 中,您可以使用

解决此问题
  1. 所有格量词:
'/(?:\(\ ?)?((?:(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)++(?:\ ?\|\ ?(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+)(?:\ ?\))?/'

注意提到的组末尾的 ++。 2. 原子团:

'/(?:\(\ ?)?((?>(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+(?:\ ?\|\ ?(?:\**\[(?:!?\d+)?\])*\**[A-Za-z_]\w*)+)(?:\ ?\))?/'

参见this regex demo。请注意 (?>...) 语法。

此外,请注意正则表达式的格式here,使用x(扩展)标志将正则表达式分成几行非常方便,格式化它,这样它就可以更容易追踪问题。它需要转义所有文字空白和 # 个字符,但在调试像这样的长模式时会带来一些不便。