为什么 \\。平等的。在preg_replace?

时间:2013-01-23 16:05:24

标签: php regex

top-voted answerthis fantastic question中,以下正则表达式用于preg_replace调用(来自答案的auto_version函数):

'{\\.([^./]+)$}'

此正则表达式的最终目标是从给定文件名中提取文件的扩展名。但是,我很困惑为什么这个正则表达式的开头有效。即:

为什么\\.与正则表达式中\.的匹配方式相同?

前者是否应该匹配(a)一个字面反斜杠,然后是(b)任何字符,而第二个匹配一个字面时间? single quoted strings的规则声明\\产生字面反斜杠。

考虑这个简单的例子:

$regex1 = '{\.([^./]+)$}';  // Variant 1 (one backslash)
$regex2 = '{\\.([^./]+)$}'; // Variant 2 (two backslashes)

$subject1 = '/css/foobar.css';   // Regular path
$subject2 = '/css/foobar\\.css'; // Literal backslash before period

echo "<pre>\n";
echo "Subject 1: $subject1\n";
echo "Subject 2: $subject2\n\n";

echo "Regex 1: $regex1\n";
echo "Regex 2: $regex2\n\n";

// Test Variant 1
echo preg_replace($regex1, "-test.\$1", $subject1) . "\n";
echo preg_replace($regex1, "-test.\$1", $subject2) . "\n\n";

// Test Variant 2
echo preg_replace($regex2, "-test.\$1", $subject1) . "\n";
echo preg_replace($regex2, "-test.\$1", $subject2) . "\n\n";
echo "</pre>\n";

输出结果为:

Subject 1: /css/foobar.css
Subject 2: /css/foobar\.css

Regex 1: {\.([^./]+)$}  <-- Output matches regex 2
Regex 2: {\.([^./]+)$}  <-- Output matches regex 1

/css/foobar-test.css
/css/foobar\-test.css

/css/foobar-test.css
/css/foobar\-test.css

长话短说:为什么\\. preg_replace调用\.为{{1}}会产生相同的匹配结果?

2 个答案:

答案 0 :(得分:11)

考虑到有双重转义:PHP看到\\.并说“好的,这真的是\.”。然后正则表达式引擎看到\.并说“好吧,这意味着一个文字点”。

如果删除第一个反斜杠,PHP会看到\.并说“这是一个反斜杠后跟一个随机字符 - 而不是单个引号或反馈符号the spec - 所以它仍然存在\.”。正则表达式引擎再次看到\.,并给出与上面相同的结果。

答案 1 :(得分:0)

Jon对完美正确答案的补充:

请考虑使用不同类型的引号(" vs ')。如果您使用',则无法包含控制字符(如新行)。使用"可以使用特殊组合\?,其中?可以是不同的东西(例如\n\t等等。)。因此,如果您希望在双引号字符串中使用实数\,则需要使用\\来转义反斜杠。请注意,使用单引号时,这不是必需的。