带有可选组的正则表达式多行模式跳过有效数据

Regex multiline mode with optional group skip valid data

考虑下一个例子:

$payload = '
ababaaabbb =%=
ababaaabbb =%=
ababaa     =%=
';

$pattern = '/^[ab]+\s*(?:=%=)?$/m';
preg_match_all($pattern, $payload, $matches);
var_dump($matches);

比赛的预期和实际结果是:

"ababaaabbb =%="
"ababaaabbb =%="
"ababaa     =%="

但是如果$payload改为

$payload = '
ababaaabbb =%=
ababaaabbb =%=
ababaa     =%'; // "=" sign removed at EOL

实际结果是

"ababaaabbb =%="
"ababaaabbb =%="

但预期是

"ababaaabbb =%="
"ababaaabbb =%="
"ababaa     "

为什么会这样?由于 ?,组 (?:=%=)? 是可选的,有效负载中的最后一个字符串也应出现在匹配结果中。

由于最后一行以 =% 结尾,您也应该将最后 = 设为可选,并为您的预期数据使用捕获组:

/^([ab]+\s*)(?:=%=?)?$/m

RegEx Demo

PS: 您的预期结果在捕获组 #1

中可用

(?:=%=)? 在您的正则表达式中是可选的。 并不意味着该组的每个部分也是可选的。

你的正则表达式只有在看到 as 和 bs 的字符串,可选的空格,然后是 (1) =%= 和行尾或 ( 2)只是行尾。如果它看到 ab 的字符串,空格,然后是 =%= 或行尾以外的任何内容,它将不起作用。所以,=% 不会起作用。

要完成您显然想做的事情,您需要将第二个 = 设为可选,如下所示:

$pattern = '/^[ab]+\s*(?:=%=?)?$/m';
// see the additional ? here^

但在这种情况下,您似乎根本不想要 =% ,这意味着您还需要发挥更多创意:

$pattern = '/^[ab]+\s*(?:(?:=%=)?$|(?==%$))/m';

Demo.

查看您当前的正则表达式图表:

=%= 可选的(查看 white spaceEnd of line 之间的分支如何分支),但是 EOL 是必需的 。这意味着 在一个或多个 ab 符号以及零个或多个空格之后,EOL 必须出现 。但是,您的第 3 行有 =% => 不匹配。

现在,当您将 $ 锚移到可选组时:

行尾现在也是 optional,匹配 1+ ab 个字符和可选空格后将返回匹配.