【问题标题】:Regex multiline mode with optional group skip valid data带有可选组跳过有效数据的正则表达式多行模式
【发布时间】:2017-06-26 13:25:27
【问题描述】:

考虑下一个例子:

$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     "

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

【问题讨论】:

  • 将行尾锚点放在可选组内:(?:=%=$)?
  • 哦,它有效!但是,怎么做? $ 在多行模式下代表“\n 或 EOL 之前”,因此,它应该适用于字符串“ababaa =%”,因为带有“=%=”的可选部分无效,但可以使用 EOL $,或者我可以把“\n”放在最后。
  • 当可选组失败(我建议的更改)时,模式不需要到达行尾即可成功,匹配停止在最后一个空格或最后一个 a 或 b如果没有空格。
  • 对我来说很奇怪:我认为如果可选(原文如此!)组匹配失败,则匹配继续进行,但不会在第一次失败时停止。
  • 哦,由于meta.stackexchange.com/questions/1555/…,我无法将您的评论标记为正确答案也许,您将其移至此处的单独帖子,我将其标记为解决方案?

标签: php regex preg-match-all pcre multiline


【解决方案1】:

看看你当前的正则表达式图:

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

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

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

【讨论】:

  • 谢谢你,很好的解释!
  • :) “眼见为实。”
【解决方案2】:

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

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

RegEx Demo

PS:您的预期结果在捕获的第 1 组中可用

【讨论】:

  • 看预期结果的最后一行。
  • 不,因为只有=%= 或者什么都不应该匹配。
  • 您的最后一行仅以=% 结尾,那么为什么该行包含在预期结果中?
  • 真实世界的问题发布在这里:stackoverflow.com/questions/41808736/… 在这种情况下,您可以看到我需要的最后一行。
  • 好的,我会单独解决这个问题。如果您认为此问题重复,请随时删除。
【解决方案3】:

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

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

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

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

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

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

Demo.

【讨论】:

  • 就我而言,可选部分是=%==%=,什么都没有。我很惊讶您的“如果它看到一串as 和bs、空格,然后是除=%= 或行尾之外的任何内容。”。我想,那个可选组 - 如果它不匹配 - 只是在 EOL 处“跳过”与$ 匹配,这导致所有字符串如“aabb =%”都匹配。
  • 好吧,如果您还想在行尾只允许=,请将我的第二个示例更改为$pattern = '/^[ab]+\s*(?:(?:=%=)?$|(?==%?$))/m';(注意% 后面的?)。如果不匹配,可选组跳过,但整个模式仍然必须匹配。想象一下,如果您从您的正则表达式中删除可选组,留下/^[ab]+\s*$/m。这与 ababaa =% 不匹配,因为空格和行尾之间有一些东西 (=%)。
猜你喜欢
  • 1970-01-01
  • 2017-06-21
  • 1970-01-01
  • 2022-06-23
  • 2016-06-06
  • 2018-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多