2013-01-23 48 views
3

top-voted answerthis fantastic question,下面的正则表达式是在preg_replace调用中使用(从答案的auto_version功能):为什么\。平等。在preg_replace?

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

这个正则表达式的最终目标是从给定的文件名中提取文件的扩展名。然而,我很困惑这个正则表达式的开始为什么起作用。即:

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

不应该前者匹配(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呼叫作为\.相同匹配的结果吗?

回答

11

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

如果去掉第一个反斜杠,PHP看到\.,并说“这是一个反斜杠后跟一个随机的 - 不是单引号或反斜杠按the spec - 所以它仍然\.”。正则表达式引擎再次看到\.并给出了与上述相同的结果。

+0

所以如果最终目标是匹配文字反斜杠,我想你必须考虑到可能发生的多层次的转义?就像'{\\\。}',产生'\\。'? –

+0

@JonahBishop:的确如此。再次,PHP字符串中的三个或四个反斜杠将最终匹配正则表达式中的文字反斜杠(除非有三个后跟一个单引号,但是您会得到该图片)。 – Jon

+0

这里的间接级别非常有趣。我明白为什么这种事情的测试用例是个好主意。谢谢你的出色答案。 –

0

的除了完全正确的答案由Jon:

请考虑不同类型的引号(" VS ')的使用。如果使用',则不能包含控制字符(如新行)。与"这是可能的,通过使用特殊组合键\?其中?可以是不同的东西(如\n,\t等)。因此,如果您想在双引号字符串中使用真实的\,则需要使用\\来避免反斜杠。请注意,使用单引号时这不是必需的。

+0

嗯,在Perl中,我会假设PHP,\\和\'被识别为\和'内' - 限定的字符串。有人可以给PHP一个明确的答案吗? –

相关问题