正則表達式(Regular Expression)就是用某種模式去匹配一類字符串的一種公式。
正則表達式使用單個字符串來描述、匹配一系列匹配某個句法規則的字符串。
正則表達式是繁瑣的,但它是強大的,學會以後的應用會讓你除了提升效率外,會給你帶來絕對的成就感。只要認真閱讀本教程,加上應用的時候進行必定的參考,掌握正則表達式不是問題。
許多程序設計語言都支持利用正則表達式進行字符串操做。php
分割,查找,匹配,替換字符串正則表達式
在PHP中有兩套正則表達式函數庫,二者功能類似,只是執行效率略有差別:函數
一套是由 PCRE(Perl Compatible Regular Expression) 庫提供的。使用「preg_」爲前綴命名的函數;
一套由 POSIX(Portable Operating System Interface of Unix )擴展提供的。使用以「ereg_」爲前綴命名的函數;this
PCRE來源於Perl語言,而Perl是對字符串操做功能最強大的語言之一,PHP的最第一版本就是由Perl開發的產品。
PCRE語法支持更多特性,比POSIX語法更強大。所以,本文主要介紹 PCRE 語法的正則表達式編碼
在PHP中,一個正則表達式分爲三個部分:分隔符、表達式和模式修飾符。.net
分隔符可使用除字母、數字、反斜線(\
)和空白字符以外的任意 ascii 字符。
最經常使用的分隔符有正斜線(/
)、hash符號(#
) 以及取反符號(~
)。設計
有一些特殊字符和非特殊的字符串組成。是決定正則表達式匹配規則的主要部分。code
用於開啓和關閉某些特定的功能/模式。教程
當使用 PCRE 函數的時候,正則表達式必須由分隔符閉合包裹。
分隔符可使用除字母、數字、反斜線(\
)和空白字符以外的任意 ascii 字符。
最經常使用的分隔符有正斜線(/
)、hash符號(#
) 以及取反符號(~
)。utf-8
/foo bar/ (合法) #^[^0-9]$# (合法) +php+ (合法) %[a-zA-Z0-9_-]% (合法)
#[a-zA-Z0-9_-]/ (非法,兩邊的分隔符不一樣) a[a-zA-Z0-9_-]a (非法,分隔符不能是字母) \[a-zA-Z0-9_-]\ (非法,分隔符不能是反斜線(`\`))
除了上面提到的分隔符,也可使用括號樣式的分隔符,左括號和右括號分別做爲開始和結束 分隔符。
{this is a pattern}
若是分隔符 在正則表達式中使用,它必須使用反斜線(\
)進行轉義。
果分隔符常常在正則表達式內出現, 最好使用其餘分隔符來提升可讀性。
/http:\/\// #http://#
須要將一個字符串放入正則表達式中使用時,能夠用 preg_quote() 函數對其進行轉義。 它的第二個參數(可選)能夠用於指定須要被轉義的分隔符。
//在這個例子中,preg_quote($word) 用於保持星號和正斜槓(/)原文涵義,使其不使用正則表達式中的特殊語義。 $textBody = "This book is */very/* difficult to find."; $word = "*/very/*"; $reg = "/" . preg_quote($word, '/') . "/"; echo $reg; // 輸出 '/\*\/very\/\*/' echo preg_replace ($reg, "<i>" . $word . "</i>", $textBody); // 輸出 'This book is <i>*/very/*</i> difficult to find.'
能夠在結束分隔符後面增長模式修飾符來影響匹配效果。
下面的例子是一個大小寫不敏感的匹配
#[a-z]#i
字符 | 描述 |
---|---|
\ | 將下一個字符標記爲一個特殊字符、或一個原義字符、或一個 向後引用。 例如,'n' 匹配字符 "n"。'n' 匹配一個換行符。序列 '\' 匹配 "" 而 "(" 則匹配 "("。 |
字符 | 描述 |
---|---|
^ |
匹配輸入字符串的開始位置 (或在多行模式下是行首) |
$ |
匹配輸入字符串的結束位置 (或在多行模式下是行尾) |
\b |
匹配一個單詞邊界,即字與空格間的位置 |
\B |
非單詞邊界匹配 |
字符 | 描述 |
---|---|
* |
匹配前面的子表達式零次或屢次。 例如,zo 能匹配 "z" 以及 "zoo"。 等價於{0,}。 |
+ |
匹配前面的子表達式一次或屢次。 例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。 |
? |
當該字符做爲量詞,表示匹配前面的子表達式零次或一次。 例如,"do(es)?" 能夠匹配 "do" 或 "does" 。? 等價於 {0,1}。 |
{n} |
n 是一個非負整數。匹配肯定的 n 次。 例如,'o{2}' 不能匹配 "Bob" 中的 'o',可是能匹配 "food" 中的兩個 o。 |
{n,} |
n 是一個非負整數。至少匹配n 次。 例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的全部 o。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。 |
{n,m} |
m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。 例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。 |
字符 | 描述 | |
---|---|---|
\d |
匹配一個數字字符。等價於 [0-9] 。 |
|
\D |
匹配一個非數字字符。等價於 [^0-9] 。 |
|
\w |
匹配字母、數字、下劃線。等價於 [A-Za-z0-9_] 。 |
|
\W |
匹配非字母、數字、下劃線。等價於 [^A-Za-z0-9_] 。 |
|
\s |
匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v] 。 |
|
\S |
匹配任何非空白字符。等價於 [^ \f\n\r\t\v] 。 |
|
. |
匹配除換行符(n、r)以外的任何單個字符。 要匹配包括 'n' 在內的任何字符,請使用像"(. |
n)"的正則表達式。 |
字符 | 描述 |
---|---|
\n |
匹配一個換行符。等價於 x0a 和 cJ。 |
\r |
匹配一個回車符。等價於 x0d 和 cM。 |
\t |
匹配一個製表符。等價於 x09 和 cI。 |
字符 | 描述 |
---|---|
| | 豎線字符 | 能夠匹配多選一的狀況。 例如,'z|food' 能匹配 "z" 或 "food"。'(z|f|g)ood' 則匹配 "zood"、"food"或 "good"。 |
字符 | 描述 |
---|---|
[x|y] | 匹配 x 或 y。 例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配 "zood" 或 "food"。 |
[xyz] |
字符集合。匹配所包含的任意一個字符。 例如, [abc] 能夠匹配 "plain" 中的 'a'。 |
[^xyz] |
負值字符集合。匹配未包含的任意字符。 例如, [^abc] 能夠匹配 "plain" 中的'p'、'l'、'i'、'n'。 |
[a-z] |
字符範圍。匹配指定範圍內的任意字符。 例如, [a-z] 能夠匹配 'a' 到 'z' 範圍內的任意小寫字母字符。 |
[^a-z] |
負值字符範圍。匹配任何不在指定範圍內的任意字符。 例如, [^a-z] 能夠匹配任何不在 'a' 到 'z' 範圍內的任意字符。 |
字符 | 描述 |
---|---|
? |
當該字符緊跟在任何一個其餘限制符 (*, +, ?, {n}, {n,}, {n,m}) 後面時,匹配模式是非貪婪的。 非貪婪模式儘量少的匹配所搜索的字符串,而默認的貪婪模式則儘量多的匹配所搜索的字符串。 例如,對於字符串 "oooo",'o+?' 將匹配單個 "o",而 'o+' 將匹配全部 'o'。 |
( )
分組字符 | 描述 |
---|---|
(pattern) |
匹配 pattern 並獲取這一匹配。要匹配圓括號字符,請使用 \( 或 \) 。 |
(?:pattern) |
匹配 pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供之後使用。這在使用 "或" 字符 (|) 來組合一個正則表達式的各個部分是頗有用。 例如, 'industr(?:y|ies) 就是一個比 'industry|industries' 更簡略的表達式。 |
(?=pattern) |
正向確定預查(look ahead positive assert),在任何匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供之後使用。 例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配以後當即開始下一次匹配的搜索,而不是從包含預查的字符以後開始。 |
(?!pattern) |
正向否認預查(negative assert),在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供之後使用。 例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配以後當即開始下一次匹配的搜索,而不是從包含預查的字符以後開始。 |
(?<=pattern) |
反向(look behind)確定預查,與正向確定預查相似,只是方向相反。 例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。 |
(?<!pattern) |
反向否認預查,與正向否認預查相似,只是方向相反。 例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。 |
若是設置了這個修飾符,正則表達式中的字母會進行大小寫不敏感匹配。
默認狀況下,PCRE 認爲目標字符串是由單行字符組成的(然而實際上它可能會包含多行)。
"行首"元字符 (^
) 僅匹配字符串的開始位置, 而"行末"元字符 ($
) 僅匹配字符串末尾, 或者最後的換行符(除非設置了 D 修飾符)。
當這個修飾符設置以後,「行首」元字符 (^
) 和「行末」元字符 ($
) 就會匹配目標字符串中任意換行符以前或以後,另外,還分別匹配目標字符串的最開始和最末尾位置。
若是目標字符串 中沒有 "n" 字符,或者正則表達式中沒有出現 ^
或 $
,設置這個修飾符不產生任何影響。
默認狀況下,點號(.
)不匹配換行符。
若是設置了這個修飾符,正則表達式中的點號元字符匹配全部字符,包含換行符。
這個修飾符與前面提到的 ?
做用相同,使正則表達式默認爲非貪婪匹配。
在使用U修飾符的狀況下,再在量詞後加 ?
,可使其轉爲貪婪匹配(負負得正)。
在非貪婪模式,一般不能匹配超過 pcre.backtrack_limit 的字符。
$str = '<b>abc</b><b>def</b>'; $pattern = '|<b>(.*)</b>|'; preg_match_all($pattern, $str, $matches);
.*
會匹配 abc</b><b>def
在使用U修飾符的狀況下,再在量詞後加 ?
,負負得正,依然是貪婪匹配
$str = '<b>abc</b><b>def</b>'; $pattern = '|<b>(.*?)</b>|U'; preg_match_all($pattern, $str, $matches);
.*
會匹配 abc</b><b>def
方法1、使用 ?
轉爲非貪婪模式
$str = '<b>abc</b><b>def</b>'; $pattern = '|<b>(.*?)</b>|'; preg_match_all($pattern, $str, $matches);
.*
會分別匹配 abc
,def
方法2、使用修飾符 U
轉爲非貪婪模式
$str = '<b>abc</b><b>def</b>'; $pattern = '|<b>(.*)</b>|U'; preg_match_all($pattern, $str, $matches);
.*
會分別匹配 abc
,def
此修正符使正則表達式和目標字符串都被認爲是 utf-8 編碼。
無效的目標字符串會致使 preg_* 函數什麼都匹配不到;無效的正則表達式字符串會致使 E_WARNING 級別的錯誤。
$str = '中文'; $pattern = '/^[\x{4e00}-\x{9fa5}]+$/u'; if (preg_match($pattern, $str)) { echo '該字符串全是中文'; } else { echo '該字符串不全是中文'; }
默認狀況下,若是使用 $
限制結尾字符,當字符串以一個換行符結尾時, $
符號還會匹配該換行符(但不會匹配以前的任何換行符)。
若是設置這個修飾符,正則表達式中的 $
符號僅匹配目標字符串的末尾。
若是設置了修飾符 m,這個修飾符被忽略。
若是設置了這個修飾符,正則表達式中的沒有通過轉義的或不在字符類中的空白數據字符總會被忽略, 而且位於一個未轉義的字符類外部的#字符和下一個換行符之間的字符也被忽略。
若是設置了這個修飾符,正則表達式被強制爲"錨定"模式,也就是說約束匹配使其僅從 目標字符串的開始位置搜索。
當一個正則表達式須要屢次使用的時候,爲了獲得匹配速度的提高,值得花費一些時間對其進行一些額外的分析。
若是設置了這個修飾符,這個額外的分析就會執行。
當前,這種對一個正則表達式的分析僅僅適用於非錨定模式的匹配(即沒有單獨的固定開始字符)。
使用 ( )
標記的開始和結束的多個原子,不只是一個獨立的單元,也是一個子表達式。
在一個 ( )
中的子表達式外面,反斜線緊跟一個大於 0 的數字,就是對以前出現的某個子表達式的後向引用。
後向引用用於重複搜索前面某個 ( )
中的子表達式匹配的文本。
(sens|respons)e and \1ibility
將會匹配 」sense and sensibility」 和 」response and responsibility」, 而不會匹配 」sense and responsibility」
<?php $str = '<b>abc</b><b>def</b>'; $pattern = '/<b>(.*)<\/b><b>(.*)<\/b>/'; $replace = preg_replace($pattern, '\\1', $str); echo $replace . "\n"; $replace = preg_replace($pattern, '\\2', $str); echo $replace . "\n";
輸出:
abc def
PHP官網的講解已經很詳細了,這裏再也不作多餘的論述
UTF-8漢字編碼範圍是 0x4e00-0x9fa5
在ANSI(GB2312)環境下,0xb0-0xf7
,0xa1-0xfe
UTF-8要使用 u模式修正符 使模式字符串被當成 UTF-8
在ANSI(GB2312)環境下,要使用chr將Ascii碼轉換爲字符
<?php $str = '中文'; $pattern = '/[\x{4e00}-\x{9fa5}]/u'; preg_match($pattern, $str, $match); var_dump($match);
<?php $str = '中文'; $pattern = '/['.chr(0xb0).'-'.chr(0xf7).']['.chr(0xa1).'-'.chr(0xfe).']/'; preg_match($pattern, $str, $match); var_dump($match);
<?php $str = '<img alt="高清大圖" id="color" src="color.jpg" />'; $pattern = '/<img.*?src="(.*?)".*?\/?>/i'; preg_match($pattern, $str, $match); var_dump($match);