2012-12-04 100 views
3

我從正則表達式中獲得了一些意想不到的結果,這意味着要替換名稱空間上的類名。替換看起來會發生兩次,以便替換的類名稱被重複(請參見下面的示例)。preg_replace雙重替換

我實際上已經解決了這個問題,通過改變reg ex來匹配1或更多(+)而不是0或更多(*),這實際上對於我想要的更準確。

但是,我有點困惑,爲什麼我首先得到一個問題。

這是問題的一個例子:

$classns = 'components\groups\GroupsController'; 
$newclass = 'GroupsAccess'; 
$classns = preg_replace('/[^\\\\]*$/', $newclass, $classns); 
echo $classns; 

結果

components\groups\GroupsAccessGroupsAccess 

預計

components\groups\GroupsAccess 

是否有可能的是,*是匹配的,一個字邊界或東西性質?

對我來說,令人困惑的部分是使用相同正則表達式的preg_match只顯示一個結果,所以它看起來像是preg_match如何運行正則表達式。

例如

preg_match('/[^\\\\]*$/', $classns, $m); 
var_dump($m); 

結果

array(1) { [0]=> string(12) "GroupsAccess" } 
+2

'preg_match_all'顯示什麼? 'preg_match' _always_最多顯示一個匹配項。 –

+0

@JanDvorak好的。它顯示兩場比賽。 –

+0

你爲什麼不直接在這裏使用str_replace? – Evert

回答

5

*不匹配字邊界,它是匹配空字符串

你的表達是在第一匹配

組件\組\ GroupsController

$是匹配的位置處的錨固件,並且是字符串的末尾(前或在字符串結尾之前的\n)。

所以在第一次匹配之後,正則表達式語法分析器的位置在最後一個「r」之後並且在字符串結束之前,當它試圖再次匹配您的正則表達式時。並且它會找到一個更匹配==>/(空字符串)出現0次,後面是字符串的結尾。

然後它繼續前進,識別字符串的結尾並結束。

+0

我有點錯過了「然後它繼續前進」的部分(如果匹配是空的,指針會被一個字符超前)。現在它非常有意義。謝謝。 –

+0

['找到第一場比賽後,從上次比賽結束後繼續進行搜索。](http://php.net/manual/en/function.preg-match-all.php)是空的匹配一個異常,或者我誤解了? –

+0

@JanDvorak,什麼是「空白匹配」?它匹配是因爲找到了定義的模式(當然它是一個空字符串)。正則表達式引擎將始終在最後找到的匹配之後繼續搜索。 – stema

2

縮小下來,這也說明了兩場比賽:

preg_match_all('/a*$/', 'a', $m);` 

Python有相同的行爲:

>>> re.findall('a*$', 'a') 
['a', ''] 

因此還包括Perl:

>>> my @m = 'a' =~ /a*$/g; 
>>> foreach (@m) { print "$_\n"; } 
a 
<blank> 

看來,正則表達式引擎匹配'a'和它後面的空字符串''。從技術上講,這是正確的,雖然這是令人驚訝的。 'a'是錨定在搜索字符串末尾的字符串,因此是''

匹配的一個基本規則是匹配不重疊。一旦找到匹配,正則表達式引擎將繼續搜索前一場比賽結束時的下一場比賽。我沒有想到的是,可以重新使用錨點$,可能是因爲它是零寬度斷言而不是實際的子字符串匹配。