程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP 正則表達式筆記,php正則表達式筆記

PHP 正則表達式筆記,php正則表達式筆記

編輯:關於PHP編程

PHP 正則表達式筆記,php正則表達式筆記


什麼是正則表達式

在電腦上我們經常會使用(通配符)找出我們需要的文件,例如:*.doc ,這裡的 * 代表匹配零個或多個字符。正則表達式也是用來進行文本匹配的工具,只不過它更加強悍。引用 PHP 手冊裡的一句話:正則表達式是一個從左到右匹配目標字符串的模式,大多數字符自身就代表一個匹配 它們自身的模式。

下面給出幾個簡單例子,使對正則表達式有個初步的理解。

hi  //匹配英文字符(忽略大小寫) hi , HI , Hi , hI
\bhi\b  //匹配英文單詞 hi  '\b'是正則裡的一特殊字符(一種斷言),表示單詞邊界
\bhi\b.*\bLucy\b  //匹配如:'hi my name is Lucy'  '.' 表示匹配除換行符以外的任意字符  '*' 是量詞,表示重復零次或更多次
0\d{2}-\d{8}  //匹配如: 020-12345678  '\d' 匹配一個數字(0-9)    '{n}' 重復n次,如{2} {8}

上面例子中的 \b , . , * , \d , {2} 都有特殊含義,在下文會有說明。

PHP 中正則語法

1.簡介

在 PHP 裡支持兩種正則分別是 POSIX 和 PCRE 。自 PHP 5.3.0起,POSIX 正則表達式擴展被廢棄。所以下文討論的都是基於 PCRE 模式。可點擊查看有關與 POSIX 正則表達式的不同和與 perl 的不同之處。

2.分隔符

當使用 PCRE 函數 的時候,模式需要由分隔符閉合包裹。分隔符可以使任意非字母數字、非反斜線、非空白字符。經常使用的分隔符是正斜線 / 、hash符號 # 以及取反符號 ~ 。下面的例子都是使用合法分隔符的模式。

/foo bar/
#^[^0-9]$#
+php+
%[a-zA-Z0-9_-]%

如果分隔符需要在模式內進行匹配,它必須使用反斜線進行轉義。如果分隔符經常在模式內出現,一個更好的選擇就是是用其他分隔符來提高可讀性。例:

/http:\/\//
#http://#

3.元字符

正則表達式的威力源於它可以在模式中擁有選擇和重復的能力。一些字符被賦予特殊的含義,使其不再單純的代表自己,模式中的這種有特殊涵義的編碼字符 稱為元字符
共有兩種不同的元字符:一種是可以在模式中方括號外任何地方使用的,另外一種是需要在方括號內使用的。

在方括號外使用的元字符如下:

代碼說明 / 一般用於轉義字符 ^ 斷言目標的開始位置(或在多行模式下是行首) $ 斷言目標的結束位置(或在多行模式下是行尾) . 匹配除換行符外的任何字符(默認) [ 開始字符類定義 ] 結束字符類定義 | 開始一個可選分支 ( 子組的開始標記 ) 子組的結束標記 ? a:作為量詞,表示 0 次或 1 次匹配。b:位於量詞後面用於改變量詞的貪婪特性。 * 量詞,0 次或多次匹配 + 量詞,1 次或多次匹配 { 自定義量詞開始標記 } 自定義量詞結束標記

模式中方括號內的部分稱為“字符類”。 在一個字符類中僅有以下可用元字符:

代碼說明 \ 轉義字符 ^ 僅在作為第一個字符(方括號內)時,表明字符類取反 - 標記字符范圍

示例:

  • \ba\w*\b 匹配以字母 a 開頭的單詞,先是某個單詞開始處 \b ,然後是字母 a ,然後是任意數量的任意單詞字符(單詞字符指的是任意字母、數字、下劃線) \w* ,最後是單詞結束處 \b 。
  • \d+ 匹配1個或更多連續的數字。
  • ^\d{5,12}$ 匹配為5位到12位數字,因為使用了 ^ 和 $ ,所以輸入的整個字符串都要用來和 \d{5,12} 來匹配,也就是說整個輸入必須是5到12個數字。

4.轉義序列(反斜線)

反斜線 \ 有四種用法,詳細可點擊 轉義序列(反斜線)

【1】作為轉義字符,比如,如果你希望匹配一個 * 字符,就需要在模式中寫為 \* 。這適用於一個字符在不進行轉義會有特殊含義的情況下。 但是,對於非數字字母的字符,總是在需要其進行原文匹配的時候在它前面增加一個反斜線,來聲明它代表自己,這是安全的。如果要匹配一個反斜線,那麼在模式中使用 \\
反斜線在單引號字符串和雙引號字符串中都有特殊含義,因此要匹配一個反斜線, 模式中必須寫為 \\\\ 。其中的原因:首先它作為字符串,反斜線會進行轉義。最後正則表達式引擎也認為反斜線是轉義。因此,需要 4 個反斜線才可以匹配一個反斜線。

【2】提供了一種對非打印字符進行可見編碼的控制手段

【3】用來描述特定的字符類

代碼說明 \d 任意十進制數字 \D 任意非十進制數字 \h 任意水平空白字符(since PHP 5.2.4) \H 任意非水平空白字符(since PHP 5.2.4) \s 任意空白字符 \S 任意非空白字符 \v 任意垂直空白字符(since PHP 5.2.4) \V 任意非垂直空白字符(since PHP 5.2.4) \w 任意單詞字符,單詞字符指的是任意字母、數字、下劃線。 \W 任意非單詞字符

【4】一些簡單的斷言。一個斷言指定一個必須在特定位置匹配的條件,它們不會從目標字符串中消耗任何字符。反斜線斷言包括:

  • \b 單詞邊界
  • \B 非單詞邊界
  • \A 目標的開始位置(獨立於多行模式)
  • \Z 目標的結束位置或結束處的換行符(獨立於多行模式)
  • \z 目標的結束位置(獨立於多行模式)
  • \G 在目標中首次匹配位置

5.重復/量詞

代碼說明 * 重復零次或更多次,等價於 + 重復一次或更多次,等價於 ? 重復零次或一次,等價於 {n} 重復n次 {n,} 重復n次或更多次 {n,m} 重復n到m次

默認情況下,量詞都是”貪婪”的,也就是說,它們會在不導致模式匹配失敗的前提下,盡可能多的匹配字符(直到最大允許的匹配次數)。然而,如果一個量詞緊跟著一個 ? 標記,它就會成為懶惰(非貪婪)模式, 它不再盡可能多的匹配,而是盡可能少的匹配。
下面直接看示例,理解“貪婪”和“非貪婪”模式是怎麼回事。

對於字符串 "aa<div>test1</div>bb<div>test2</div>cc"

正則表達式 "<div>.*</div>"    匹配結果 "<div>test1</div>bb<div>test2</div>"

正則表達式 "<div>.*?</div>"   匹配結果 "<div>test1</div>"

關於更多“貪婪”和“非貪婪”模式的介紹可查閱 http://php.net/manual/zh/regexp.reference.repetition.php

6.字符類(方括號)

PHP手冊中的描述:

  • 左方括號開始一個字符類的描述,並以方中括號結束。單獨的一個右方括號沒有特殊含義。如果一個右方括號需要作為一個字符類中的成員,那麼可以將它寫在字符類的首字符處(如果使用了 ^ 取反,那麼是第二個)或者使用轉義符。

  • 一個字符類在目標字符串中匹配一個單獨的字符;該字符必須是字符類中定義的字符集合的其中一個, 除非使用了 ^ 對字符類取反。如果^需要作為一個字符類的成員,確保它不是該字符類的首字符,或者對其進行轉義即可。

示例:

[aeiou]    //匹配所有的小寫元音字母

[^aeiou]   //匹配所有非元音字母的字符

[.?!]      //匹配標點符號(.或?或!)

注意:^ 只是一個通過枚舉指定那些不存在字符類之中的字符的便利符號。而不是斷言, 它仍然會從目標字符串中消耗一個字符,並且如果當前匹配點在目標字符串末尾, 匹配將會失敗。

輕松地指定一個字符范圍,范圍操作以 ASCII 整理排序。它們可以用於為字符指定數值,比如 [\000-\037]

[0-9]    //代表的含意與 '\d' 就是完全一致的
[a-z0-9A-Z_]    //完全等同於 '\w' 如果只考慮英文的話

下面是一個更復雜的表達式 \(?0\d{2}[) -]?\d{8}
這個表達式可以匹配幾種格式的電話號碼,像 (010)88886666,或 022-22334455 ,或 02912345678 等。
簡單分析:首先是一個轉義字符 \( ,它能出現 0 次或 1 次 ? ,然後是一個數字 0 ,後面跟著 2 個數字 \d{2} ,然後是 )- 或 “空格” 中的一個,它出現 0 次或 1 次,最後是 8 個數字 \d{8}

7.分支 ( | )

豎線字符用於分離模式中的可選路徑。比如模式 gilbert|Sullivan 匹配 ”gilbert” 或者 ”sullivan”。豎線可以在模式中出現任意多個,並且允許有空的可選路徑(匹配空字符串)。匹配的處理從左到右嘗試每一個可選路徑,並且使用第一個成功匹配的。如果可選路徑在子組(下面定義)中,則”成功匹配”表示同時匹配了子模式中的分支以及主模式中的其他部分。

回看上文裡的一個例子 \(?0\d{2}[) -]?\d{8} 這個正則也能匹配 010)12345678 或 (022-87654321 這樣的 “不正確” 的格式。其實我們可以利用分支就能解決這個問題,如下:

\({1}0\d{2}\){1}[- ]?\d{8}|0\d{2}[- ]?\d{8} 這個表達式匹配 3 位區號的電話號碼,其中區號可以用小括號括起來,也可以不用,區號與本地號間可以用連字號或空格間隔,也可以沒有間隔。

使用分枝條件時,要注意各個條件的順序

8.內部選項設置

正則表達式在不同的模式修飾符下匹配出的結果有可能不相同。它的語法是 :(?修飾符)

比如,(?im) 設置表明多行大小寫不敏感匹配。同樣可以用它來取消這些設置,比如 (?im-sx) 設置了 “PCRE_CASELESS”,”PCRE_MULTILINE”,但是同時取消了 “PCRE_DOTALL” 和 “PCRE_EXTENDED”。如果一個字母即出現在 - 之前, 也出現在 - 之後,這個選項被取消設置。

下面緊例舉簡單的示例,想要了解更多可點擊 內部選項設置 和 模式修飾符

示例:/ab(?i)c/ 僅僅匹配 ”abc” 和 ”abC”

9.子組(子模式)

子組通過圓括號分隔界定,並且它們可以嵌套。

示例:

字符串:"the red king"
正則表達式:((red|white) (king|queen))
匹配結果:array("red king", "red king", "red", "king")
描述:其中第 0 個元素是整個模式匹配的結果,後面的三個元素依次為三個子組匹配的結果。 它們的下標分別為 1, 2, 3。

經常我們會有一種需求需要使用子組進行分組,但又不需要(單獨的)捕獲它們。在子組定義的左括號後面緊跟字符串 ?: 會使得該子組不被單獨捕獲,並且不會對其後子組序號的計算產生影響。例如:

字符串:"the red king"
正則表達式:((?:red|white) (king|queen))
匹配結果:array("red king", "red king", "king")

為了方便簡寫,如果需要在非捕獲子組開始位置設置選項, 選項字母可以位於 ?: 之間,比如:

(?i:saturday|sunday)
(?:(?i)saturday|sunday)

上面兩種寫法實際上是相同的模式。因為可選分支會從左到右嘗試每個分支,並且選項沒有在子模式結束前被重置,並且由於選項的設置會穿透對後面的其他分支產生影響,因此, 上面的模式都會匹配 ”SUNDAY” 以及 ”Saturday”。

再看一個匹配 IP 地址的正則 ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
相關文章 IP地址的正則表達式

結語

上文中涉及 PHP 正則表達式中常用的語法,有的語法沒細說和涉及到的,如:模式修飾符、後向引用、斷言、遞歸模式,等。你可以通過 PHP 手冊查看這些內容。

提示:一般而言,對於同樣的功能,正則表達式函數運行效率要低於字符串函數。如果應用程序較簡單,那麼就用字符串表達式。但是,對於可以通過單個正則表達式執行的任務來說,如果使用多個字符串函數,則是不對的。 ---- 摘自《PHP 和 MySQL Web 開放》一書。

參考資料

http://php.net/manual/zh/book.pcre.php
https://msdn.microsoft.com/zh-cn/library/d9eze55x%28v=vs.80%29.aspx
http://deerchao.net/tutorials/regex/regex.htm
http://tool.chinaz.com/regex/
http://www.regexlab.com/zh/regref.htm

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved