奇怪的 preg_match_all() 行为

问题描述 投票:0回答:1

我有这个代码来处理配置文件:

<?php
$config = '[log]
log_writers[] = "file"
log_writers[] = "screen"

[General]
maintenance_mode = 0
enable_browser_archiving_triggering = 0
enable_sql_optimize_queries = 0
force_ssl = 1';

echo preg_match_all( '/^maintenance_mode[ \t]*=[ \t]*\d$/m', $config );

回波显示

0

https://onlinephp.io/c/51407

将正则表达式更新为:

echo preg_match_all( '/^maintenance_mode[ \t]*=[ \t]*\d\s$/m', $config );

达到预期效果

1

为什么??


我什至在 regex101 中验证了我的理智

https://regex101.com/r/CIxCkN/1


本地测试环境:

RHEL 7
PHP 5.6.25
PCRE v8.32 2012-11-30

Windows Server 2022
PHP 8.2.7
PCRE v10.40 2022-04-14

php regex preg-match-all
1个回答
3
投票

一个答案是您的字符串(或通常的脚本)具有 Windows 行结尾。

在多行模式下,

\d$
仅匹配数字后跟一个立即换行符(由PCRE的编译时设置确定),如果其中隐藏了
\r
,则可能无法工作。

在正则表达式末尾添加

\s
将匹配所有行结束字符,这解释了为什么这对受影响的测试环境有帮助。

对于修复(除了您已经找到的

\s
添加之外),PCRE 允许您使用字符串开头的修饰符来调整哪些字符匹配为换行符,例如
(*ANYCRLF)

// Force Windows line-ending
<?php
$test = "foo\r\nbar";

var_dump(preg_match_all('/^foo$/m', $test));
var_dump(preg_match_all('/(*ANYCRLF)^foo$/m', $test));

int(0)
整数(1)

请参阅 https://3v4l.org/vOUgM 进行演示,并参阅 PCRE 文档换行约定部分了解一些详细信息。

或者,只需在字符串中使用 PCRE 在本地期望的换行符。

© www.soinside.com 2019 - 2024. All rights reserved.