PHP Regex 非贪婪匹配在某些服务器上无法正常工作

问题描述

我有以下最小示例,它们在本地服务器(WAMP、PHP 7.3.7)和使用 PHP 7.3.27 的生产服务器上的行为不同。本地服务器上的结果对我来说似乎是错误的,因为惰性修饰符被忽略了。结果也和我试过的所有正则表达式测试器都有冲突。

示例代码

<?PHP
header('Content-Type: text/plain; charset=utf-8');

$input = <<<EOT
John Smith
John Smith (123)
John Smith (123) (456)
EOT;


preg_match_all('/(.+?)(?:\s\((\d+)\))?$/m',$input,$matches_defines);
print_r($matches_defines);

?>

本地环境中的结果:

Array
(
    [0] => Array
        (
            [0] => John Smith
            [1] => John Smith (123)
            [2] => John Smith (123) (456)
        )

    [1] => Array
        (
            [0] => John Smith
            [1] => John Smith (123)
            [2] => John Smith (123)
        )

    [2] => Array
        (
            [0] => 
            [1] => 
            [2] => 456
        )
)

生产环境中的结果:

Array
(
    [0] => Array
        (
            [0] => John Smith
            [1] => John Smith (123)
            [2] => John Smith (123) (456)
        )

    [1] => Array
        (
            [0] => John Smith
            [1] => John Smith
            [2] => John Smith (123)
        )

    [2] => Array
        (
            [0] => 
            [1] => 123
            [2] => 456
        )
)

谁能告诉我这种差异来自哪里,可以在当地环境中进行哪些调整来纠正它?

解决方法

好的,在这里回答我自己的问题:这是一个 Windows/Linux 行尾问题。

我本地服务器上的正则表达式失败,因为在文本中,每个右括号后面都有一个 \r。所以右括号不是行尾,在行尾(\r)之前还有一个额外的字符$。 (Source)

这可以通过稍微修改的正则表达式来解决:/(.+?)(?:\s\((\d+)\))?\s*$/m。 请注意末尾的 \s*。这与行尾的 \r 匹配(如果存在)。