php 中正則表示式詳解
概述
正則表示式是一種描述字串結果的語法規則,是一個特定的格式化模式,可以匹配、替換、擷取匹配的字串。常用的語言基本上都有正則表示式,如JavaScript、java等。其實,只有瞭解一種語言的正則使用,其他語言的正則使用起來,就相對簡單些。文字主要圍繞解決下面問題展開。
- 有哪些常用的轉義字元
- 什麼是限定符與定位符
- 什麼是單詞定位符
- 特殊字元有哪些
- 什麼是逆向引用以及怎樣使用逆向引用
- 匹配模式
- php中怎樣使用正則表示式
- php中哪些方面需要用到正則
- 怎樣進行郵箱匹配,url匹配,手機匹配
- 怎樣使用正則替換字串中某些字元
- 貪婪匹配與惰性匹配區別
- 正則表示式之回溯與固態分組
- 正則優缺點有哪些
正則表示式的基本知識彙總
行定位符(^與$)
行定位符是用來描述字串的邊界。“$”
表示行結尾“^”
表示行開始如"^de"
,表示以de開頭的字串 "de$"
,表示以de結尾的字串。
單詞定界符
我們在查詢的一個單詞的時候,如an是否在一個字串”gril and body”中存在,很明顯如果匹配的話,an肯定是可以匹配字串“gril and body”匹配到,怎樣才能讓其匹配單詞,而不是單詞的一部分呢?這時候,我們可以是喲個單詞定界符\b。
\ban\b 去匹配”gril and body”的話,就會提示匹配不到。
當然還有一個大寫的\B,它的意思,和\b正好相反,它匹配的字串不能使一個完整的單詞,而是其他單詞或字串中的一部分。如\Ban\B。
選擇字元(|) ,表示或
選擇字元表示或的意思。如Aa|aA,表示Aa或者是aA的意思。注意使用”[]”與”|”的區別,在於”[]”只能匹配單個字元,而”|”可以匹配任意長度的字串。在使用”[]”的時候,往往配合連線字元”-“一起使用,如[a-d],代表a或b或c或d。
排除字元,排除操作
正則表示式提供了”^”來表示排除不符合的字元,^一般放在[]中。如[^1-5],該字元不是1~5之間的數字。
限定符(?*+{n,m})
限定符主要是用來限定每個字串出現的次數。
限定字元 | 含義 |
---|---|
? | 零次或一次 |
* | 零次或多次 |
+ | 一次或多次 |
{n} | n次 |
{n,} | 至少n次 |
{n,m} | n到m次 |
如(D+)表示一個或多個D
點號操作符
匹配任意一個字元(不包含換行符)
表示式中的反斜槓(\
)
表示式中的反斜槓有多重意義,如轉義、指定預定義的字符集、定義斷言、顯示不列印的字元。
轉義字元
轉義字元主要是將一些特殊字元轉為普通字元。而這些常用特殊字元有”.”,”?”、”\”等。
指定預定義的字符集
字元 | 含義 |
---|---|
\d | 任意一個十進位制數字[0-9] |
\D | 任意一個非十進位制數字 |
\s | 任意一個空白字元(空格、換行符、換頁符、回車符、字表符) |
\S | 任意一個非空白字元 |
\w | 任意一個單詞字元 |
\W | 任意個非單詞字元 |
###顯示不可列印的字元
字元 | 含義 |
---|---|
\a | 報警 |
\b | 退格 |
\f | 換頁 |
\n | 換行 |
\r | 回車 |
\t | 字表符 |
括號字元()
在正則表示式中小括號的作用主要有:
- 改變限定符如(|、* 、^)的作用範圍
如(my|your)baby,如果沒有”()”,|將匹配的是要麼是my,要麼是yourbaby,有了小括號,匹配的就是mybaby或yourbaby。 - 進行分組,便於反向引用
反向引用
反向引用,就是依靠子表示式的”記憶”功能,匹配連續出現的字串或是字元。如(dqs)(pps)\1\2,表示匹配字串dqsppsdqspps。在下面php應用中,我將詳細展開學習反向引用。
模式修飾符
模式修飾符的作用是設定模式,也就是正則表示式如何解釋。php中主要模式如下表:
修飾符 | 說明 |
---|---|
i | 忽略大小寫 |
m | 多文字模式 |
s | 單行文字模式 |
x | 忽略空白字元 |
正則表示式在php中應用
php中字串匹配
所謂的字串匹配,言外之意就是判斷一個字串中,是否包含或是等於另一個字串。如果不使用正則,我們可以使用php中提供了很多方法進行這樣的判斷。
不使用正則匹配
- strstr函式
string strstr ( string haystack,mixedneedle [, bool $before_needle = false ])- 注1:haystack是當事字串,needle是被查詢的字串。該函式區分大小寫。
- 注2:返回值是從needle開始到最後。
- 注3:關於$needle,如果不是字串,被當作整形來作為字元的序號來使用。
- 注4:before_needle若為true,則返回前東西。
- stristr函式與strstr函式相同,只是它不區分大小寫
- strpo函式
int strpos ( string haystack,mixedneedle [, int $offset = 0 ] )
注1:可選的 offset 引數可以用來指定從 haystack 中的哪一個字元開始查詢。返回的數字位置是相對於 haystack 的起始位置而言的。 - stripos -查詢字串首次出現的位置(不區分大小定)
- strrpos -計算指定字串在目標字串中最後一次出現的位置
- strripos -計算指定字串在目標字串中最後一次出現的位置(不區分大小寫)
使用正則進行匹配
在php中,提供了preg_math()和preg_match_all函式進行正則匹配。關於這兩個函式原型如下:
int preg_match|preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
搜尋subject與pattern給定的正則表示式的一個匹配.
pattern:要搜尋的模式,字串型別。
subject :輸入字串。
matches:如果提供了引數matches,它將被填充為搜尋結果。 matches[0]將包含完整模式匹配到的文字,matches[1]將包含第一個捕獲子組匹配到的文字,以此類推。
flags:flags可以被設定為以下標記值:PREG_OFFSET_CAPTURE 如果傳遞了這個標記,對於每一個出現的匹配返回時會附加字串偏移量(相對於目標字串的)。 注意:這會改變填充到matches引數的陣列,使其每個元素成為一個由 第0個元素是匹配到的字串,第1個元素是該匹配字串 在目標字串subject中的偏移量。
offset:通常,搜尋從目標字串的開始位置開始。可選引數 offset 用於 指定從目標字串的某個未知開始搜尋(單位是位元組)。
返回值:preg_match()返回 pattern 的匹配次數。 它的值將是0次(不匹配)或1次,因為 preg_match()在第一次匹配後 將會停止搜尋。 preg_match_all()不同於此,它會一直搜尋subject直到到達結尾。 如果發生錯誤 preg_match()返回 FALSE。
例項
- 例項1
判斷字串”http://blog.csdn.net/hsd2012“中是否包含csdn?
解法一(不適用正則):
如果不適用正則,我們使用strstr或者strpos中任意一個都可以,在此,我將使用strstr函式,程式碼如下:
$str='http://blog.csdn.net/hsd2012';
function checkStr1($str,$str2)
{
return strstr1($str,$str2)?true:false;
}
echo checkStr($str,'csdn');
解法二:使用正則
因為我們只需要判斷是否存在即可,所以選擇preg_match。
$str='http://blog.csdn.net/hsd2012';
$pattern='/csdn/';
function checkStr2($str,$str2)
{
return preg_match($str2,$str)?true:false;
}
echo checkStr2($str,$pattern);
- 例項2(考察單詞定界符)
判斷字串”I am a good boy”中是否包含單詞go
首先判斷是單詞,而不是字串,因此比較的時候,需要比較是否包含’ go ‘,即在字串go前後有一個空格。
解析:如果使用非正則比較,只需要呼叫上面的checkStr1()函式即可,注意,第二個引數前後要加一個空格,即’ go ‘。如果使用正則,
我們可以考慮使用單詞定界符\b,那麼$pattern=’/\bgo\b/’;然後呼叫checkStr2函式即可. - 例3(考察反向引用)
判斷字串”I am a good boy”中是否包含3個相同的字母
解析:此時,如果我們不使用正則,將會很難判斷,因為字母太多了,我們不可能去將所有字母分別與該字串比較,那樣工作量也比較大。這時候涉及到了正在的反向引用。在php正則表示式中,通過\n,來表示第n次匹配到的結果。如\5代表第五次匹配到的結果。那麼本題的$pattern='/(\w).*\1.*\1/';
主要注意的是,在使用反向匹配的時候都需要使用(),反向匹配時,匹配()裡面出現的字元或字串。
php中字串替換
不使用正則
php中當替換字串的時候,如果不適用正則,我們通常使用substr、mb_substr、str_replace、substr_replace關於這幾個函式區別如下表。
函式符 | 功能 | 描述 |
---|---|---|
str_replace(find,replace,string,count) | 使用一個字串替換字串中的另一些字元。 | find 必需。規定要查詢的值。replace 必需。規定替換 find 中的值的值。string 必需。規定被搜尋的字串。count 可選。一個變數,對替換數進行計數。 |
substr_replace(string,replacement,start,length) | 把字串的一部分替換為另一個字串。適合用於替換自定位置的字串。 | string 必需。規定要檢查的字串。replacement 必需。規定要插入的字串。start 必需。規定在字串的何處開始替換。 |
使用正則
如果使用正則替換,php中提供了preg_replace _callback和preg_replace 函式,preg_replace 原型如下:
mixed preg_replace ( mixed pattern,mixedreplacement , mixed subject[,intlimit = -1 [, int &count]])函式功能描述:在字串subject中,查詢pattern,然後使用replacement 去替換,如果有limit則代表限制替換limit次。pregreplacecallback與pregreplace功能相識,不同的是pregreplaceback使用一個回撥函式callback來代替replacement.−例1將字串”hello,中國”中的hello替換為′你好′;如果不是用正則:str=’hello,中國’;
str=strreplace(′hello′,′你好′,str)
或是使用str=substrreplace(str,’你好’,0,5)
使用正則
pattern=′/hello/′;str=preg_replace (pattern,′你好′,str);
- 例2
去除字串”gawwenngeeojjgegop”中連續相同的字母
$str='gawwenngeeojjgegop';
$pattern='/(.)\1/';
$str=preg_replace($pattern,'',$str);
解析:當然這樣可能會遇到,當第一次去除了重複了字串後,又出來重複的字串。如字串味’gewwenngeeojjgegop’,針對這中問題,當然,這樣的話,通過判斷,繼續替換下去。
- 例3
將字串中”age13gegep3iorji65k65k”;中出現的連續兩個數字改為第二個數字,如字串中13被改為3
$str='age13gegep3iorji65k65k';
$pattern='/(\d)(\d)/';
$str=preg_replace($pattern,'$2', $str);
解析:$n在正則表示式外使用反向引用。n代表第幾次匹配到的結果。
php中字串分割
不適用正則
php提供了explode函式去分割字串,與其對應的是implode。關於explode原型如下:
array explode ( string delimiter,stringstring [, int $limit ] )
delimiter:邊界上的分隔字元。
string:輸入的字串。
limit:如果設定了 limit 引數並且是正數,則返回的陣列包含最多 limit 個元素,而最後那個元素將包含 string 的剩餘部分。如果 limit 引數是負數,則返回除了最後的 -limit 個元素外的所有元素。如果 limit 是 0,則會被當做 1。
使用正則
關於通過正則表示式進行字串分割,php提供了split、preg_split 函式。preg_split() 函式,通常是比 split() 更快的替代方案。
array preg_split ( string pattern,stringsubject [, int limit=−1[,intflags = 0 ]] )
- 例題
將字串 ‘http://blog.csdn.net/hsd2012/article/details/51152810‘按照’/’進行分割
解法一:
$str='http://blog.csdn.net/hsd2012/article/details/51152810';
$str=explode('/', $str);
解法二:
$str='http://blog.csdn.net/hsd2012/article/details/51152810';
$pattern='/\//'; /*因為/為特殊字元,需要轉移*/
$str=preg_split ($pattern, $str);
php中貪婪匹配與惰性匹配
- 貪婪匹配:就是匹配儘可能多的字元。
比如,正則表示式中m.*n,它將匹配最長以m開始,n結尾的字串。如果用它來搜尋manmpndegenc的話,它將匹配到的字串是manmpndegen而非man。可以這樣想,當匹配到m的時候,它將從後面往前匹配字元n。 - 懶惰匹配:就是匹配儘可能少的字元。
有的時候,我們需要並不是去貪婪匹配,而是儘可能少的去匹配。這時候,就需要將其轉為惰性匹配。怎樣將一個貪婪匹配轉為惰性匹配呢?只需要在其後面新增一個”?”即可。如m.*?n將匹配manmpndegenc,匹配到的字串是man。
函式符 | 描述 |
---|---|
*? | 零次或多次,但儘可能少的匹配 |
+? | 一次或多次,但儘可能少的匹配 |
?? | 0次或1次,但儘可能少的匹配 |
{n,}? | 至少n次,但儘可能少的匹配 |
{n,m}? | n到m次 ,但儘可能少的匹配 |
php正則表示式之回溯與固態分組
回溯
首先我們需要清楚什麼是回溯,回溯就像是在走岔路口,當遇到岔路的時候就先在每個路口做一個標記。如果走了死路,就可以照原路返回,直到遇見之前所做過的標記,標記著還未嘗試過的道路。如果那條路也走不能,可以繼續返回,找到下一個標記,如此重複,直到找到出路,或者直到完成所有沒有嘗試過的路。首先我們看例題
$str='aageacwgewcaw';
$pattern='/a\w*c/i';
$str=preg_match($pattern, $str);
看到上面的程式,可能都清楚是什麼意思,就是匹配$str是否包含這樣一個由”a+0個或多個字母+c”不區分大小寫的字串。但是至於程式怎樣去匹配的呢?匹配的過程中,回溯了多少次呢?
匹配過程 | 接下來操作描述 |
---|---|
‘a\w*c’中a匹配到’aageacwgewcaw’中第一個字元a | \w進行下一個字元匹配 |
因為\w是貪婪匹配,會一直匹配到’aageacwgewcaw’中最後一個字元w | c進行下一個字元匹配時 |
‘a\w*c’中c發現沒有可以匹配的 | 於是\w匹配進行第一次回溯,匹配到倒數第二個字元a |
‘a\w*c’中c發現還是沒有可以匹配的 | 於是\w匹配進行第二次回溯,匹配到倒數第三個字元c |
‘a\w*c’中c匹配成功 | 匹配結束返回結果 |
現在,如果我們將pattern改為pattern=’/a\w*?c/i’;又會回溯多少次呢?正確答案是回溯四次。
固態分組
固態分組,目的就是減少回溯次數, 使用(?>…)括號中的匹配時如果產生了備選狀態,那麼一旦離開括號便會被立即 引擎拋棄掉。舉個典型的例子如: ‘\w+:’這個表示式在進行匹配時的流程是這樣的,會優先去匹配所有的符合\w的字元,假如字串的末尾沒有’:’,即匹配沒有找到冒號,此時觸發回溯機制,他會迫使前面的\w+釋放字元,並且在交還的字元中重新嘗試與’:’作比對。但是問題出現在這裡: \w是不包含冒號的,顯然無論如何都不會匹配成功,可是依照回溯機制,引擎還是得硬著頭皮往前找,這就是對資源的浪費。所以我們就需要避免這種回溯,對此的方法就是將前面匹配到的內容固化,不令其儲存備用狀態!,那麼引擎就會因為沒有備用狀態可用而只得結束匹配過程。大大減少回溯的次數。
如下程式碼,就不會進行回溯:
$str='nihaoaheloo';
$pattern='/(?>\w+):/';
$rs=preg_match($pattern, $str);
當然有的時候,又需慎用固態分組,如下,我要檢查$str中是否包含以a結尾的字串,很明顯是包含的,但是因為使用了固態分組,反而達不到我們想要的效果
$str='nihaoahelaa';
$pattern1='/(?>\w+)a/';
$pattern2='/\w+a/';
$rs=preg_match($pattern1, $str);//0
$rs=preg_match($pattern2, $str);//1
php中其他常用字串操作函式
- 字串擷取擷取
string substr ( string string,intstart [, int length])stringmbsubstr(stringstr , int start[,intlength = NULL [, string $encoding = mb_internal_encoding() ]] ) - 字串中大小寫轉換
strtoupper
strtolower
ucfirst
ucwords - 字串比較
-strcmp、strcasecmp、strnatcmp - 字串過濾
- 字串翻轉
strrev($str); - 字串隨機排序
string str_shuffle ( string $str )
補充
怎樣進行郵箱匹配,url匹配,手機匹配
使用preg_match函式進行匹配,以下內容從TP中複製而來。
郵箱驗證
pattern=′/\w+([−+.]\w+)∗@\w+([−.]\w+)∗\.\w+([−.]\w+)∗/’;
url匹配
pattern='/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(:\d+)?(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?/’;
手機驗證
pattern=′/1[3458]\d10/’;
php中正則的優缺點
php中正則在某些時候,能幫我們解決php函式很多困難的匹配或是替換。然後php中正則的效率,往往是我們需要考慮的,所以在某些時候,能不用正則還是儘量不去用它,除非,某些場合必須用到,或是我們能夠有效減少其回溯次數。