奇怪的 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 中,您可以使用
解决此问题
- 所有格量词:
'/(?:\(\ ?)?((?:(?:\**\[(?:!?\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
(扩展)标志将正则表达式分成几行非常方便,格式化它,这样它就可以更容易追踪问题。它需要转义所有文字空白和 #
个字符,但在调试像这样的长模式时会带来一些不便。
我的 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 中,您可以使用
解决此问题- 所有格量词:
'/(?:\(\ ?)?((?:(?:\**\[(?:!?\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
(扩展)标志将正则表达式分成几行非常方便,格式化它,这样它就可以更容易追踪问题。它需要转义所有文字空白和 #
个字符,但在调试像这样的长模式时会带来一些不便。