2013-01-23 47 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一個明確的答案嗎? –

相關問題