1. 程式人生 > >PHP強化之11 - PCRE正則表示式

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

參考:

官方手冊:http://php.net/manual/zh/pcre.pattern.php