PHP強化之11 - PCRE正則表示式
一、簡介
正則表示式是一種描述字串結果的語法規則,是一個特定的格式化模式,可以匹配、替換、擷取匹配的字串。
二、語法
當使用 PCRE 函式的時候,模式需要由分隔符閉合包裹。分隔符可以使任意非字母數字、非反斜線、非空白字元。經常使用的分隔符是正斜線(/)、hash符號(#) 以及取反符號(~)。
合法模式示例:
/<\/\w+>/ #^[^0-9]$# |(\d{3})-\d+|Sm ## 可以在結束分隔符後面增加模式修飾符 /^(?i)php[34]/ {^\s+(\s+)?$} ## 括號樣式的分隔符,左括號和右括號分別作為 開始和結束 分隔符。 %[a-zA-Z0-9_-]%
非法模式示例:
/href='(.*)' ## 缺失結束分隔符
/\w+\s*\w+/J ## 未知模式修飾符"J"
1-\d3-\d3-\d4| ## 缺失開始分隔符
如果分隔符需要在模式內進行匹配,它必須使用反斜線進行轉義。如果分隔符經常在 模式內出現, 一個更好的選擇就是是用其他分隔符來提高可讀性。
/http:\/\//
#http://#
三、正則表示式
由上面介紹的合法分隔符所包含的部分,就是我們主要去了解的正則表示式部分了。下面我將對一些常用的部分做一下歸類:
1、 原子
原子是組成正則表示式的基本單位,在分析正則表示式時,應作為一個整體。
包括以下內容:
> 單個字元、數字,如a-z,A-Z,0-9。
> 模式單元,如(ABC)可以理解為由多個原子組成的大的原子。
> 原子表,如 [ABC]。
> 重新使用的模式單元,如:\1
> 普通轉義字元,如:\d, \D, \w
> 轉義元字元,如:\*,\.
> 元字元
2、元字元
- ^ 斷言目標的開始位置(或在多行模式下是行首)
- $ 斷言目標的結束位置(或在多行模式下是行尾)
- . 表示任意一個除換行符之外的字元
- [] 表示單個字元的原子表
[^] 表示除中括號內原子之外的任何字元 是[]的取反
[-] 表示允許的範圍,如[0-9]表示任意一位數字 - {m} 表示對前面原子的數量控制,表示是m次
{m,} 表示對前面原子的數量控制,表示是至少m次
{m,n}表示對前面原子的數量控制,表示是m到n次 - * 量詞,0 次或多次匹配,等價於{0,}
- + 量詞,1 次或多次匹配,等價於{1,}
- ? 作為量詞,表示 0 次或 1 次匹配,等價於{0,1} 。位於量詞後面用於改變數詞的貪婪特性。
- () 表示一個整體原子,【還有一個子儲存單元的作用】。 也可以使用
?:
來拒絕子儲存。 (?:.*?) - | 開始一個可選分支
3、常用轉義字元
說明 | |
---|---|
\d | 匹配一個數字;等價於[0-9] |
\D | 匹配除數字以外任何一個字元;等價於[^0-9] |
\w | 匹配一個英文字母、數字或下劃線;等價於[0-9a-zA-Z_] |
\W | 匹配除英文字母、數字和下劃線以外任何一個字元;等價於[^0-9a-zA-Z_] |
\s | 匹配一個空白字元;等價於[\f\n\r\t\v] |
\S | 匹配除空白字元以外任何一個字元;等價於[^\f\n\r\t\v] |
\n | 匹配一個換行符 |
\r | 匹配一個回車符 |
4、模式修整符
- i 表示不區分大小寫;
如:"/[a-zA-Z]/"
等價於"/[a-z]/i"
- s 表示匹配視為單行
如果設定了這個修飾符,模式中的點號元字元匹配所有字元,包含換行符。如果沒有這個 修飾符,點號不匹配換行符。 - U 表示拒絕貪婪匹配
通過量詞後緊跟? 的方式可以使其成為貪婪的,注意這和 模式修整符U 是不能同時使用的,只能取其一。 - x 忽略空白字元
5、惰性匹配
函式符 | 描述 |
---|---|
*? | 零次或多次,但儘可能少的匹配 |
+? | 一次或多次,但儘可能少的匹配 |
?? | 0次或1次,但儘可能少的匹配 |
{n,}? | 至少n次,但儘可能少的匹配 |
{n,m}? | n到m次 ,但儘可能少的匹配 |
四、相關函式
1、preg_match
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
搜尋subject與pattern給定的正則表示式的一個匹配。
如果提供了引數matches,它將被填充為搜尋結果。 $matches[0]將包含完整模式匹配到的文字, $matches[1] 將包含第一個捕獲子組匹配到的文字,以此類推。
函式返回值為0或1。
如:
$label = 'content/112abc';
$a = preg_match('#content/(\d+)(\w*)#i', $label, $mc);
var_dump($a);
var_dump($mc);
結果:
int(1)
array(3) {
[0] =>
string(14) "content/112abc"
[1] =>
string(3) "112"
[2] =>
string(3) "abc"
}
注意:
preg_match() 第一次匹配成功後就會停止匹配,如果要實現全部結果的匹配,即搜尋到subject結尾處,則需使用preg_match_all() 函式。
2、preg_match_all
int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )
搜尋subject中所有匹配pattern給定正則表示式 的匹配結果並且將它們以flag指定順序輸出到matches中。在第一個匹配找到後, 子序列繼續從最後一次匹配位置搜尋。
該函式返回完整匹配次數(可能是0),或者如果發生錯誤返回FALSE。
引數說明:
引數 | 說明 |
---|---|
pattern | 正則表示式 |
subject | 需要匹配檢索的物件 |
matches | 儲存匹配結果的陣列 |
flags | 可選,指定匹配結果放入 matches 中的順序,可供選擇的標記有: 1)PREG_PATTERN_ORDER:預設,對結果排序使 $matches[0] 為全部模式匹配的陣列,$matches[1] 為第一個括號中的子模式所匹配的字串組成的陣列,以此類推 2)PREG_SET_ORDER:對結果排序使 $matches[0] 為第一組匹配項的陣列,$matches[1] 為第二組匹配項的陣列,以此類推 3)PREG_OFFSET_CAPTURE:如果設定本標記,對每個出現的匹配結果也同時返回其附屬的字串偏移量 |
如:
$userinfo = "Name: <b>PHP</b> <br> Title: <b>Programming Language</b>";
preg_match_all ("/<b>(.*)<\/b>/U", $userinfo, $pat_array);
print_r($pat_array[0]);
結果:
Array
(
[0] => <b>PHP</b>
[1] => <b>Programming Language</b>
)
3、preg_replace
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜尋subject中匹配pattern的部分, 以replacement進行替換。
$string = 'April 15, 2003';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}1,$3';
echo preg_replace($pattern, $replacement, $string);
//輸出:April1,2003
4、preg_split
通過一個正則表示式分隔給定字串.
array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )
如:
//使用逗號或空格(包含" ", \r, \t, \n, \f)分隔短語
$keywords = preg_split("/[\s,]+/", "hypertext language, programming");
print_r($keywords);
結果:
Array
(
[0] => hypertext
[1] => language
[2] => programming
)
5、其它
1)preg_grep
array preg_grep ( string $pattern , array $input [, int $flags = 0 ] )
返回給定陣列input中與模式pattern 匹配的元素組成的陣列
2)preg_quote
string preg_quote ( string $str [, string $delimiter = NULL ] )
轉義正則表示式字元
五、經典例項
1、關於URL
1)從url中取得主機名
$url = "http://blog.nosee123.com/index.php";
preg_match("/^(http:\/\/)?([^\/]+)/i",$url, $matches);
$host = $matches[2]; // 結果為:string(15) "blog.snsgou.com"
2)判斷字串判斷是否為url
/^http(s?):\/\/([\w]+\.?)++\/*[\w\.]*\??[\w=&\+\%]*/is
2、關於Email
1)判斷字串是否是郵箱
/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
^[a-zA-Z0-9][a-zA-Z0-9._-]*@[a-zA-Z0-9]+\.[a-zA-Z0-9\.]+$
2)只允許英文字母、數字、下劃線、英文句號、以及中劃線組成
//[email protected]
^[a-zA-Z0-9_-][email protected][a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
3、關於字元
1)任意一位大小字母或數字下劃線:
[A-Za-z0-9_] 等價於 \w
4、數字相關
1)手機號碼
[1][3-8][0-9]{9} //粗略匹配
^((13[0-9])|147|(15[0-35-9])|180|182|(18[5-9]))[0-9]{8}$
Or:
# 中國大陸手機號 (移動/聯通/電信):
/^1(3[0-9]|4[5-9]|5[0-35-9]|66|7[013-8]|8[0-9]|9[89])\d{8}$/
# 中國移動:
/^1(34[0-8]|3[5-9\d]|440|4[78]\d|5[0-27-9]\d|70[356]|78\d|8[2-478]\d|98\d)\d{7}$/
# 中國聯通:
/^1(3[0-2]\d|4[56]\d|5[56]\d|66\d|70[4789]|71|7[56]\d|8[56]\d)\d{7}$/
# 中國電信:
/^1(3[3]\d|349|410|49\d|53\d|70[0-2]|7[37]\d|740|8[019]\d|99\d)\d{7}$/
2)ip地址
\d+\.\d+\.\d+\.\d+
3)身份證
^(([0-9]{15})|([0-9]{18})|([0-9]{17}x))$
5、中文匹配
中文匹配:UTF-8漢字編碼範圍是0x4e00-0x9fa5;在ANSI(gb2312)環境下,0xb0-0xf7,0xa1-0xfe。
UTF-8要使用u模式修正符使模式字串被當成UTF-8,在ANSI(gb2312環境下),使用chr將Ascii碼轉換為字元。
[\x{4e00}-\x{9fa5}] #utf-8中文
[\u4e00-\u9fa5] #通用
5、HTML頁面的匹配
1)取出頁面中所有img標籤的src值
'/<img.*?src=("|\')(.*?)("|\').*?\/?>/i'
2)判斷是否為a連結
/<a .*?href="(.*?)".*?>/is