正規表示式入門教學(簡明版)

2020-07-16 10:05:10
“正規表示式”描述在搜尋文字正文時要匹配的一個或多個字串,該表示式可用作與要搜尋的文字相比較的字元模式。

可以使用正規表示式來搜尋字串中的模式、替換文字以及提取子字串。

正規表示式的用途

典型的搜尋和替換操作要求提供與預期的搜尋結果匹配的確切文字,雖然這種技術對靜態文字執行簡單搜尋和替換任務可能已經足夠了,但它缺乏靈活性,採用這種方法搜尋動態文字將會變得比較困難。

正規表示式可以讓你靈活地從字串中匹配出特定格式的文字。

通過使用正規表示式可以測試字串內的模式,例如:
  • 可以測試輸入字串,以檢視字串內是否出現電話號碼模式或信用卡號碼模式,這稱為資料驗證。
  • 替換文字,可以使用正規表示式來識別文件中的特定文字、完全刪除該文字或者用其他文字替換。
  • 基於模式匹配從字串中提取子字串,可以查詢文件內或輸入域內特定的文字。

有時我們可能需要搜尋整個網站、刪除過時的材料以及替換某些 HTML 格式標記。在這種情況下,可以使用正規表示式來確定在每個檔案中是否出現該材料或該 HTML 格式標記。此過程將受影響的檔案列表縮小到包含需要刪除或更改的材料的那些檔案,然後可以使用正規表示式來刪除過時的材料。最後,使用正規表示式來搜尋和替換標記。

正規表示式的語法

正規表示式的結構與所建立的算術表示式的結構類似,較大的表示式可由小的表示式通過使用各種元字元和運算子進行組合而建立。

正規表示式的各組成部分可以是單個字元、字元集、字元範圍或在幾個字元之間選擇,也可以是這些組成部分的任意組合。

通過在一對分隔符之間放置表示式的各種組成部分就可以構建正規表示式。例如在 PHP 中,分隔符是一對正斜槓/字元,如以下範例所示:

/^(d+)?.d+$/

正規表示式的構成

正規表示式的構成元素中一般包括普通字元、元字元、限定符、定位點、非列印字元和指定替換項等。

普通字元

最簡單的正規表示式是與搜尋字串相比較的單個普通字元。例如,單字元正規表示式 A 會始終匹配字母 A,無論其會出現在搜尋字串的哪個位置。

可以將多個單字元組合起來以形成較長的表示式,例如,正規表示式/the/會匹配搜尋字串中的 "the""the""there""other" 和 "over the lazy dog"。無須使用任何串聯運算子,只需連續輸入字元即可。

元字元

除普通字元之外,正規表示式還可以包含“元字元”。其中,元字元又可分為單字元元字元和多字元元字元。例如,元字元d,它與數位字元相匹配。

普通字元包括沒有顯式指定為元字元的所有可列印和不可列印字元,包括所有大小寫字母、數位、標點符號和一些符號。

下表中列出了所有的單字元元字元。

單字元元字元
元字元 行為 範例
* 零次或多次匹配前面的字元或子表示式,等效於{0,} zo* 與 “z”和“zoo”匹配
+ 一次或多次匹配前面的字元或子表示式,等效於{1,} zo+ 與 “zo”和“zoo”匹配,但與“z”不匹配
? 零次或一次匹配前面的字元或子表示式,等效於{0,1}
當 ? 緊隨任何其他限定符(*、+、?、{n}、{n,} 或 {n,m})之後時,匹配模式是非貪婪的。非貪婪模式匹配搜尋到的、盡可能少的字串,而預設的貪婪模式匹配搜尋到的、盡可能多的字串
zo? 與“z”和“zo”匹配,但與“zoo”不匹配
o+? 只與“oooo”中的單個“o”匹配,而 o+ 與所有“o”匹配
do(es)? 與“do”或“does”中的“do”匹配
^ 匹配搜尋字串開始的位置。如果標誌中包括 m(多行搜尋)字元,^ 還將匹配 n 或 r 後面的位置。如果將 ^ 用作括號表示式中的第一個字元,就會對字元集取反 ^d{3} 與搜尋字串開始處的 3 個字元匹配
[^abc] 與除 a、b、c 以外的任何字元匹配
$ 匹配搜尋字串結束的位置。如果標誌中包括 m(多行搜尋)字元,^ 還將匹配 n 或 r 前面的位置。 d{3}$ 與搜尋字串結尾處的 3 個數位匹配
. 匹配除換行符 n 之外的任何單個字元。若要匹配包括 n 在內的任意字元,請使用諸如 [sS] 之類的模式 a.c 與 “abc”“a1c”和“a-c”匹配
[] 標記括號表示式的開始和結尾 [1-4] 與“1”、“2”、“3”或“4”匹配
[^aAeEiIoOuU] 與任何非元音字元匹配
{} 標記限定符表示式的開始和結尾 a{2,3} 與“aa”和“aaa”匹配
() 標記子表示式的開始和結尾,可以儲存子表示式,以備將來之用 A(d) 與“A0”至“A9”匹配。儲存該數位以備將來之用
| 指示兩個或多個項之間進行選擇 z|food 與“z”或“food”匹配
(z|f)ood 與 “zood”或“food”匹配
/ 表示 JavaScript 中的文字正規表示式模式的開始和結尾。在第二個 “/”後新增單字元標誌可以指定搜尋行為 /abc/gi 是與 “abc”匹配的 JavaScript 文字正規表示式。g(全域性)標誌指定查詢模式的所有匹配項,i(忽略大小寫)標誌使搜尋不區分大小寫
將下一字元標記為特殊字元、文字、反向參照或八進位制跳脫符 n 與換行符匹配。( 與 “(”匹配。 與 “”匹配

這些特殊字元在括號表示式內出現時失去它們的意義,並表示普通字元。若要匹配這些特殊字元,必須首先跳脫字元,即在字元前面加反斜槓字元。例如,若要搜尋+文字字元,則可使用表示式+

除了以上單字元元字元外,還有一些多字元元字元,如表所示。

多字元元字元
元字元 行為 範例
b 與一個字邊界匹配。即字與空格間的位置 erb 與 “never”中的“er”匹配,但與“verb”中的“er”不匹配
B 非邊界字匹配 erB 與“verb”中的“er”匹配,但與“never”中的“er”不匹配
d 數位字元匹配,等效於[0-9] 在搜尋字串“12 345”中,d{2} 與“12”和“34”匹配。d 與“1”,“2”、“3”、“4”和“5”匹配
D 非數位字元匹配,等效於[^0-9] /D+ 與“abc123 def”中的“abc”和“def”匹配
w 與 A-Z、a-z、0-9 和下劃線中的任意任意字元匹配,等效於[A-Za-z0-9] 在搜尋字串“The quick brown fox...”中,w+ 與“The”、“quick”、“brown”和“fox”匹配
W 與除 A-Z、a-z、0-9 和下劃線以外的任意字元匹配,等效於[^A-Za-z0-9] 在搜尋字串“The quick brown fox...”中,W+ 與“...”和所有空格匹配
[xyz] 字元集,與任何一個指定字元匹配 [abc] 和 “plain”中的“a”匹配
[^xyz] 反向字元集,與未指定的任何字元匹配 [^abc] 與“plain”中的“p”、“1”、“i”和“n”匹配
[a-z] 字元範圍,匹配指定範圍內的任何字元 [a-z] 與“a”到“z”範圍內的任何小寫字母字元匹配
[^a-z] 反向字元範圍,與不在指定範圍內的任何字元匹配 [^a-z] 與不在範圍“a”到“z”內的任何字元匹配
{n} 正好匹配 n 次,n 是非負整數 o{2} 與“Bob”中的“o”不匹配,但與“fooood”中的兩個“o”匹配
{n,} 至少匹配 n 次,n 是非負整數
* 與 {0,} 相等
+ 與 {1,} 相等
o{2} 與“Bob”中的“o”不匹配,但與“fooood”中的所有“o”匹配
{n,m} 匹配至少 n 次,至多 m 次。n 和 m 是非負整數,其中 n<= m,逗號和數位之間不能有空格
? 與 {0,1} 相等
在搜尋字串“1234567”中,d{1,3} 與“123”、“456”和“7”匹配
(模式) 與模式匹配並儲存匹配項。可以從由 JavaScript 中的 exec Method 返回的陣列元素中檢索儲存的匹配項。若要匹配括號字元(),請使用“(”或者“)” (Chapter|Section) [1-9] 與 “Chapter 5”匹配,儲存“Chapter”以備將來之用
(?:模式) 與模式匹配,但不儲存匹配項,即不會儲存匹配項以備將來之用。這對於用“or”字元(|)組合模式部件的情況很有用 industry(?:y|ies) 與 industry|industries 相等
(?=模式) 正預測先行。找到一個匹配項後,將在匹配文字之前開始搜尋下一個匹配項。不會儲存匹配項以備將來之用 ^(?=_.*d.{4,8}$ 對密碼應用一下限制:
其長度必須介於 4 到 8 字元之間,並且必須至少包含一個數位,在該模式中,*d 查詢後跟有數位的任意多個字元。對於搜尋字串“abc3qr”,與“abc3”匹配。
從該匹配項之前,(而不是之後)開始,{4,8} 與包含 4~8 個字元的字串匹配,與“abc3qr”匹配。
^ 和 $ 指定搜尋字串的開始和結束位置,將在搜尋字串包含匹配字元之外的任何字元時阻止匹配
(?!模式) 負預測先行。匹配與模式不匹配的搜尋字串。找到一個匹配項後,將在匹配文字之前開始搜尋下一個匹配項。不會儲存匹配項以備將來之用 b(?!th)/w+b 與不以“th”開頭的單詞匹配在該模式中,b 與一個字邊界匹配。對於搜尋字串“quick”,與第一個空格匹配。(?!th) 與非“th”字串匹配與“qu”匹配,從該匹配項開始,!w+ 與一個字匹配,即與“quick”匹配
cx 匹配 x 指示的控制字元。x 的值必須在 A-Z 或 a-z 範圍內。如果不是這樣,就假定 c 是文字“c”字元本身 cM 與 Ctrl+M 或一個回車符匹配
xn 匹配 n,此處的 n 是一個十六進位制跳脫碼。十六進位制跳脫碼必須正好是兩位數長。允許在正規表示式中使用 ASCII 程式碼 x41 與“A”匹配、x41 等效於後跟有“1”的“x04”(因為 n 必須正好是兩位數)
num 匹配 num,此處的 num 是一個正整數。這是對以儲存的匹配項的參照 (.)1 與兩個連續的相同字元匹配
n 標識一個八進位制跳脫碼或反向參照。如果 n 前面至少有 n 個捕獲子表示式,那麼 n 是反向參照;否則,如果 n 是八進位制數(0-7),那麼 n 是八進位制跳脫碼 (d)1 與兩個連續的相同數位匹配
nm 標識一個八進位制跳脫碼或反向參照。如果 nm 前面至少有 nm 個捕獲子表示式,那麼 nm 是反向參照。如果 nm 前面至少有 n 個捕獲子表示式,則 n 是反向參照,後面跟有文字 m。如果上述情況都不存在,當 n 和 m 是八進位制數位(0-7)時,nm 匹配八進位制跳脫碼 nm 11 與製表符匹配
nml 當 n 是八進位制數位(0-3)、m 和 1 是八進位制數位(0-7)時,匹配八進位制跳脫碼 nml 11 與製表符匹配
un 匹配 n,其中 n 是以 4 位十進位制數位表示的 Unicode 字元 u00A9 與版權符號(©?)匹配

非列印字元

非列印字元是由普通字元跳脫、用來在正規表示式中匹配特定行為的字元,如換行、換頁、空白符等。下表列出了非列印字元。

非列印字元
字元 匹配 等效於
f 換頁符 x0c 和 cL
n 換行符 x0a 和 cJ
r 回車符 x0d 和 cM
s 任何空白字元,包括空格、製表符和換頁符 [fbrtv]
S 任何非空白字元 [^fbrtv]
t Tab 字元 x09 和 cI
v 垂直製表符 x0b 和 cK

優先順序順序

正規表示式的計算方式與算術表示式非常類似,即從左到右進行計算,並遵循優先順序順序,如表所示。

正規表示式優先順序
運算子 說明 運算子 說明
跳脫符 ^、$、 任何元字元 定位點和序列
(),(?:),(?=),[] 括號和中括號 | 替換
*、+、{n}、{n,}、{n,m} 限定符    

另外,字元具有高於替換運算子的優先順序,例如,允許 "m|food" 匹配 "m" 或 "food"。

替換

正規表示式中的替換允許對兩個或多個替換選項之間的選擇進行分組。實際上可以在模式中指定兩種匹配模式的或關係。可以使用管道|字元指定兩個或多個替換選項之間的選擇,稱之為“替換”。匹配管道字元任一側最大的表示式。

例如:

/Chapter|Section [1-9][0-9]{0,1}/

該正規表示式匹配的是字串“Chapter”或者字串“Section”後跟一個或兩個數位。

如果搜尋字串是“Section 22”,那麼該表示式匹配“Section 22”。但是,如果搜尋字串是“Chapter 22”,那麼表示式匹配單詞“Chapter”,而不是匹配“Chapter 22”。

為了解決這種形式的表示式可能帶來的誤導,可以使用括號來限制替換的範圍,即確保它只應用於兩個單詞“Chapter”和“Section”。可以通過新增括號來使正規表示式匹配“Chapter 1”或“Section 3”。將以上表示式改成如下形式:

/(Chapter|Section) [1-9][0-9]{0,1}/

修改後,如果搜尋字串是“Section 22”,那麼該表示式匹配“Section 22”。如果搜尋字串是“Chapter 22”,那麼表示式匹配單詞也會是“Chapter 22”。

子表示式

正規表示式中放置括號可建立子表示式,子表示式允許匹配搜尋文字中的模式並將匹配項分成多個單獨的子匹配項,程式可檢索生成的子匹配項。

例如匹配郵箱賬號的正規表示式:

/(w+)@(w+).(w+)/

該正規表示式包含 3 個子表示式,3 個子表示式分別進行匹配並保留匹配結果,與其他表示式匹配結果作為一個整體顯示出來。

下面的範例將通用資源指示符(URI)分解為其元件:

/(w+)://([^/:]+)(:d*)?([^# ]*)/

第一個括號子表示式儲存 Web 地址的協定部分,匹配在冒號和兩個正斜槓前面的任何單詞。

第二個括號子表示式儲存地址的域地址部分,匹配不包括左斜線/或冒號字元的任何字元序列。

第三個括號子表示式儲存網站埠號(如果指定了的話),匹配冒號後面的零個或多個數位。

第四個括號子表示式儲存 Web 地址指定的路徑和/或頁資訊,匹配零個或多個數位字元#或空白字元之外的字元。

如果我們使用這個正規表示式匹配字串“http://msdn.microsoft.com:80/scripting/default.htm”,那麼 3 個子表示式的匹配結果分別為 http、msdn.microsoft.com:80、/scripting/default.htm。

反向參照

反向參照用於查詢重複字元組。此外,可使用反向參照來重新排列輸入字串中各個元素的順序和位置,以重新設定輸入字串的格式。

可以從正規表示式和替換字串中參照子表示式。每個子表示式都由一個編號來標識,並稱作反向參照。

在正規表示式中,每個儲存的子匹配項按照它們從左到右出現的順序儲存。用於儲存子匹配項的緩衝區編號從 1 開始,最多可儲存 99 個子表示式。在正規表示式中,可以使用 n 來存取每個緩衝區,其中 n 標識特定緩衝區的一位或兩位十進位制數位。

反向參照的一個應用是,提供查詢文字中兩個相同單詞的匹配項的能力。以下面的句子為例:

Is is the cost of of gasoline going up up?

該句子包含多個重複的單詞。如果能設計一種方法定位該句子,而不必查詢每個單詞的重複出現,就會很有用。

下面的正規表示式使用單個子表示式來實現這一點:

/b([a-z]+) 1b/

在此情況下,子表示式是括在括號中的所有內容。該子表示式包括由 [a-z]+ 指定的一個或多個字母字元。正規表示式的第二部分是對以前儲存的子匹配項的參照,即單詞的第二個匹配項正好由括號表示式匹配。1 用於指定第一個子匹配項。b 單詞邊界元字元確保只檢測單獨的單詞。否則,諸如“is issued”或“this is”之類的詞組將不能正確地被此表示式識別。所以,使用表示式 /b([a-z]+)1b/ 匹配字串“Is is the cost of of gasoline going up up?”得到的結果為 is、of、up。

在 PHP 中使用正規表示式

PHP 有兩套函數庫支援的正規表示式處理操作:
  • 一套是由 PCRE(Perl Compatible Regular Expression)庫提供、與 Perl 語言相容的正規表示式函數,以preg_為函數的字首名稱;
  • 另一套是 POSIX(Portable Operating System Interface)擴充套件語法正規表示式函數,以ereg_為函數的字首。

兩套函數庫的功能相似,但是 PCRE 的執行效率高於 POSIX,所以我們只介紹 PCRE 函數庫。