【问题标题】:Difference in matching end of line with PHP regex与 PHP 正则表达式匹配行尾的差异
【发布时间】:2019-03-12 13:18:36
【问题描述】:

给定代码:

$my_str = '
Rollo is*
My dog*
And he\'s very*
Lovely*
';

preg_match_all('/\S+(?=\*$)/m', $my_str, $end_words);
print_r($end_words);

在 PHP 7.3.2 (XAMPP) 中,我得到了意外的输出

Array ( [0] => Array ( ) )

而在PhpFiddle 中,在 PHP 7.0.33 上,我得到了我的预期:

Array ( [0] => Array ( [0] => is [1] => dog [2] => very [3] => Lovely ) )

为什么我会有这种差异? 7.0.33 之后正则表达式的行为是否发生了变化?

【问题讨论】:

  • 一个有用的测试网站是否是版本差异,而不是平台或配置,是3v4l.org 在这种情况下it shows the expected output for all versions 所以在你的测试环境中还有一些其他的差异。我的猜测与 Windows 与 Unix 行尾有关。
  • 在测试上述代码时,我无法重现您的问题。 Here's a demo。测试 7.1.25 - 7.3.3 并给出预期结果。如果您检查“eol 版本”,它甚至可以工作,它测试 4.3 的所有版本
  • 通过命令行使用 7.3.3 我看到了同样的故障(空数组)。
  • 我在 Ubuntu 机器上通过 CLI 在 7.3.2 和 7.3.3 上进行了测试,它仍然给了我预期的结果。
  • @WiktorStribiżew 我不会说这很容易或显而易见,但谢谢:-)

标签: php regex php-7 php-7.3


【解决方案1】:

似乎在您拥有的环境中,PCRE 库是在没有PCRE_NEWLINE_ANY 选项的情况下编译的,而多行模式下的$ 仅匹配 LF 符号之前,. 匹配除 LF 之外的任何符号。

您可以使用 PCRE (*ANYCRLF) 动词来修复它:

'~(*ANYCRLF)\S+(?=\*$)~m'

(*ANYCRLF) 指定换行符约定:(*CR)(*LF)(*CRLF),等效于 PCRE_NEWLINE_ANY 选项。见PCRE documentation

PCRE_NEWLINE_ANY 指定应识别任何 Unicode 换行序列。

最后,这个 PCRE 动词使 . 可以匹配任何字符 CR 和 LF 符号,$ 将匹配这两个字符中的任何一个。

rexegg.com查看更多关于这个和其他动词:

默认情况下,在编译 PCRE 时,您会告诉它在遇到 . 时要考虑换行符(因为点与换行符不匹配,除非在 dotall mode 中),以及 @ 987654341@ 和 $ 锚点在 multiline mode 中的行为。您可以使用以下修饰符覆盖此默认值:

(*CR)只有回车才被认为是换行
(*LF) 只有换行才被认为是换行符(在 Unix 上)
(*CRLF) 只有回车后跟换行才被认为是换行符(如在 Windows 上)
(*ANYCRLF)以上三项中任意一项都视为换行
(*ANY) 任何 Unicode 换行序列都被认为是换行符

例如,(*CR)\w+.\w+ 匹配 Line1\nLine2,因为点能够匹配 \n,这不被视为换行符。见the demo

【讨论】:

  • 多么奇怪。我唯一能想到的是,当我安装 XAMPP 时,我取消了“安装 Perl”的选择。我知道 PCRE 是从 Perl 派生的,所以这可能是造成这种情况的原因吗?
  • @Utkanos 我不相信它有任何影响。问题在于如何编译 PCRE 库。注意 PCRE 正则表达式库与 Perl 中使用的不同。
猜你喜欢
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 2012-01-14
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多