天天看點

php正則逆向引用與子模式分析

先看一個例子:

php正則逆向引用與子模式分析
php正則逆向引用與子模式分析

<?php
$string = 'April 15, 2003';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}1,$3';
echo preg_replace($pattern, $replacement, $string);
?>      

View Code

例子的結果是:April1,2003

函數preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])

在 subject 中搜尋 pattern 模式的比對項并替換為 replacement。如果指定了 limit,則僅替換 limit 個比對,如果省略 limit 或者其值為 -1,則所有的比對項都會被替換。

replacement可以包含\\n形式或$n形式的逆向引用,n可以為0到99,\\n表示比對pattern第n個子模式的文本,\\0表示比對整個pattern的文本。

所謂“子模式”就是:$pattern參數中被圓括号括起來的正規表達式(pattern即為模式)。

對上面例子中的 $replacement = '${1}1,$3';  

因為當在替換模式下工作并且後向引用後面緊跟着需要是另外一個數字, 不能使用\\1這樣的文法來描述後向引用。\\11将會使preg_replace() 不能了解你希望的是一個\\1後向引用緊跟一個原文1,還是 一個\\11後向引用後面不跟任何東西。 這種情況下解決方案是使用\${1}1。 這建立了一個獨立的$1後向引用, 一個獨立的原文1。

再看一個例子:

php正則逆向引用與子模式分析
php正則逆向引用與子模式分析
<?php 
$string = "Is is the cost of of gasoline going up up"; 
$pattern = "/\b([a-z]+) \\1\b/i"; //這裡的\\1不能使用\$1或$1 
$str = preg_replace($pattern, "\\1", $string); //這裡的\\1可以使用\$1或$1,引用第一個子比對 
echo $str; 
?>       

結果為:Is the cost of gasoline going up    去掉了重複的内容。

例中的子表達式就是圓括号内的項。\b比對單詞的開始或結束。+比對重複一次或更多次。 

該子表達式比對的是一個或多個字母字元的單詞,即由'[a-z]+'比對的。 

該正規表達式的第二部分是對前面所捕獲的子比對的引用,也就是由附加表達式所比對的第二次出現的單詞,用'\\1'來引用第一個子比對,第一個\是轉義符。 

i是正規表達式中的修正符。i:忽略大小寫。 

擴充:一個常見的面試題

在file.txt中按行存放着這樣的一些數字

0013223544456

013423545456

1372-35--45456

132245-44556

13723-584456

1392-3544-456

132-255444-56

0132-275444-56

希望對其進行處理:除去首位的0,除去字元串中包含的-符号,并且将手機号碼處理成132****456格式,處理後儲存在newfile.txt檔案中。

我的方法是:

php正則逆向引用與子模式分析
php正則逆向引用與子模式分析
<?php
$fp = fopen("file.txt", "r");
$newf = fopen("newfile.txt", "w"); 
while(! feof($fp)) 
{ 
$fgets = fgets($fp);
$fgets = preg_replace('/^0*|\D/', '', $fgets);
$pattern = "/(1\d{1,2})\d\d(\d{0,3})/";
$replacement = "\$1****\$3";
$fgets = preg_replace($pattern, $replacement, $fgets);
$text = $fgets."\r\n";
fwrite($newf, $text);

} 
fclose($fp); 
fclose($newf);
?>      

newfile.txt中最總結果是:

132****456

134****456

137****456

132****556

139****456