在top-voted answer至this 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}}会产生相同的匹配结果?
答案 0 :(得分:11)
考虑到有双重转义:PHP看到\\.
并说“好的,这真的是\.
”。然后正则表达式引擎看到\.
并说“好吧,这意味着一个文字点”。
如果删除第一个反斜杠,PHP会看到\.
并说“这是一个反斜杠后跟一个随机字符 - 而不是单个引号或反馈符号the spec - 所以它仍然存在\.
”。正则表达式引擎再次看到\.
,并给出与上面相同的结果。
答案 1 :(得分:0)
Jon对完美正确答案的补充:
请考虑使用不同类型的引号("
vs '
)。如果您使用'
,则无法包含控制字符(如新行)。使用"
可以使用特殊组合\?
,其中?
可以是不同的东西(例如\n
,\t
等等。)。因此,如果您希望在双引号字符串中使用实数\
,则需要使用\\
来转义反斜杠。请注意,使用单引号时,这不是必需的。