歡迎您光臨本站 註冊首頁

專門為初學者編寫的正規表示式入門教程

←手機掃碼閱讀     hongdian2012 @ 2020-05-11 , reply:0

這是一篇翻譯文章。我學過很多次正規表示式,總是學了忘,忘了學,一到用的時候還是隻能靠搜尋引擎。 這回看到這個正則教程,感覺非常驚喜。嘗試翻譯了一遍,譯得不好,大家可以看原文,很容易理解。 原文地址:https://refrf.shreyasminocha.me/
1 介紹
正規表示式允許定義一種模式,並透過這種模式針對字串執行對應的操作。與模式匹配的子字串稱為「匹配」。
正規表示式是定義搜尋模式的一串字元。
正規表示式主要用在如下場景:
輸入驗證
查詢替換操作
高階字串操作
檔案搜尋或重新命名
白名單和黑名單
正規表示式不太適合用在這些場景:
XML 或 HTML 解析
完全匹配的日期
有許多實現正則匹配的引擎,每種都有自己的特性。這本書將避免討論(不同引擎之間的)特性差異,而是隻討論在大多數情況下不同引擎都共有的特徵。
整本書中的示例使用JavaScript。因此,這本書可能會稍微偏向 JavaScript 的正則引擎。
2 基礎
正規表示式通常格式化為 /

/,通常為了簡潔而省略後面的 /。關於 flag 我們將在下一章詳細討論。
讓我們從 /p/g 這個正規表示式開始。現在,請將 /g flag 視為固定不變的。
/p/g
如我們所見, /p/g 匹配所有小寫的 p 字元。
注意 預設情況下,正規表示式區分大小寫。
在輸入字串中找到的正規表示式模式的例項稱為「匹配」。
/pp/g
3 字元組
可以從一組字元中匹配一個字元。
/[aeiou]/g
[aeiou]/g 匹配輸入字串中的所有母音。
下面是另一個例子:
/p[aeiou]t/g
我們匹配一個 p,後跟一個母音,然後是一個 t。
有一個更直觀的快捷方式,可以在一個連續的範圍內匹配一個字元。
/[a-z]/g
警告 表示式 /[a-z]/g 只匹配一個字元。在上面的示例中,每個字元都有一個單獨的匹配項。不是整個字串匹配。
我們也可以在正規表示式中組合範圍和單個字元。
/[A-Za-z0-9_-]/g
我們的正規表示式 /[A-Za-z0-9_-]/g 匹配一個字元,該字元必須(至少)是以下字元之一:
A-Z
a-z
0-9
_ 或者 -
我們也可以「否定」這些規則:
/[^aeiou]/g
/[aeiou]/g 與 /[^aeiou]/g 之間的唯一區別是 ^ 緊跟在左括號之後。其目的是"否定"括號中定義的規則。它表示的意思是:
匹配任何不屬於a、e、i、o和 u 的字元
3.1 例子
非法的使用者名稱字元
/[^a-zA-Z_0-9-]/g
指定字元
/[A-HJ-NP-Za-kmnp-z2-9]/g
4 字元轉義
字元轉義是對某些通用字元類的簡略表達方式。
4.1 數字字元 d
轉義符 d 表示匹配數字字元 0-9。等同於 [0-9] 。
/d/g (這裡請仔細看)
/dd/g
D 是 d 的反面,相當於 [^0-9] 。
/D/g
4.2 單詞字元 w
轉義符 w 匹配單詞字元。包括:
小寫字母 a-z
大寫字母 A-Z
數字 0-9
下劃線 _
等價於 [a-zA-Z0-9_]
/w/g
/W/g
4.3 空白字元 s
轉義符 s 匹配空白字元。具體匹配的字符集取決於正規表示式引擎,但大多數至少包括:
空格
tab 製表符
回車  
換行符
換頁 f
其他還可能包括垂直製表符(v)。Unicode自識別引擎通常匹配分隔符類別中的所有字元。然而,技術細節通常並不重要。
/s/g
/S/g (大寫 s)
4.4 任意字元 .
雖然不是典型的字元轉義。 . 可以匹配任意1個字元。(除換行符
以外,透過 dotall 修飾符,也可以匹配換行符

/./g
5 轉義
在正規表示式中,有些字元有特殊的含義,我們將在這一章中進行探討:
|
{,}
(,)
[,]
^ , $
, + , * , ?
, ,
. 只在字元類中的字面量。
只在字元類中的字面量。 - : 有時是字元類中的特殊字元。
當我們想透過字面意思匹配這些字元時,我們可以再這些字元前面加  「轉義」它們。
/(paren)/g
/(paren)/g
/example.com/g
/example.com/g
/A+/g
/A+/g
/worth $5/g
/worth $5/g
5.1 例子
JavaScript 內聯註釋
///.*
星號包圍的子串
/*[^*]**
第一個和最後一個星號是字面上的,所有他們要用 * 轉義。字符集裡面的星號不需要被轉義,但為了清楚起見,我還是轉義了它。緊跟在字符集後面的星號表示字符集的重複,我們將在後面的章節中對此進行探討。
6 組
顧名思義,組是用來「組合」正規表示式的元件的。這些組可用於:
提取匹配的子集
重複分組任意次數
參考先前匹配的子字串
增強可讀性
允許複雜的替換
這一章我們先學組如何工作,之後的章節還會有更多例子。
6.1 捕獲組
捕獲組用(…)表示。下面是一個解釋性的例子:
/a(bcd)e/g
捕獲組允許提取部分匹配項。
/{([^{}]*)}/g
透過語言的正則函式,您將能夠提取括號之間匹配的文字。
捕獲組還可以用於對正規表示式進行部分分組,以便於重複。雖然我們將在接下來的章節中詳細介紹重複,但這裡有一個示例演示了組的實用性。
/a(bcd)+e/g
其他時候,它們用於對正規表示式的邏輯相似部分進行分組,以提高可讀性。
/(dddd)-W(dd)/g
6.2 回溯
回溯允許引用之前捕獲的子字串。
匹配第一組可以使用 1 ,匹配第二組可以使用 2 ,依此類推…
/([abc])×1×1/g
不能使用回溯來減少正規表示式中的重複。它們指的是組的匹配,而不是模式。
/[abc][abc][abc]/g
/[abc]11/g
下面是一個演示常見用例的示例:
/w+([,|])w+1w+/g
這不能透過重複的字元類來實現。
/w+[,|]w+[,|]w+/g
6.3 非捕獲組
非捕獲組與捕獲組非常相似,只是它們不建立「捕獲」。而是採取形式 (?: ...)
非捕獲組通常與捕獲組一起使用。也許您正在嘗試使用捕獲組提取匹配的某些部分。而你可能希望使用一個組而不擾亂捕獲順序,這時候你應該使用非捕獲組。
6.4 例子
查詢字串引數
/^?(w+)=(w+)(?:&(w+)=(w+))*$/g
我們單獨匹配第一組鍵值對,因為這可以讓我麼使用 & 分隔符, 作為重複組的一部分。
(基礎的) HTML 標籤
根據經驗,不要使用正規表示式來匹配 XML/HTML。不過,我還是提供相關的一個例子:
/<([a-z]+)+>(.*)/gi
姓名
查詢: (w+) (w+)
替換:
在替換操作,經常使用 2;捕獲使用 1 , 2
替換之前
John Doe
Jane Doe
Sven Svensson
Janez Novak
Janez Kranjski
Tim Joe
替換之後
Doe, John
Doe, Jane
Svensson, Sven
Novak, Janez
Kranjski, Janez
Joe, Tim
回溯和複數
查詢: word(s?)
替換: phrase$1
替換之前
This is a paragraph with some words.
Some instances of the word "word" are in their plural form: "words".
替換之後
This is a paragraph with some phrases.
Yet, some are in their singular form: "phrase".
7 重複
重複是一個強大而普遍的正規表示式特性。在正規表示式中有幾種表示重複的方法。
7.1 可選項
我們可以使用 ?將某一部分設定成可選的(0或者1次)。
/a?/g
另一個例子:
/https?/g
我們還可以讓捕獲組和非捕獲組程式設計可選的。
/url: (www.)?example.com/g
7.2 零次或者多次
如果我們希望匹配零個或多個標記,可以用 * 作為字尾。
/a*/g
我們的正規表示式甚至匹配一個空字串。
7.3 一次或者多次
如果我們希望匹配 1 個或多個標記,可以用 + 作為字尾。
/a+/g
7.4 精確的 x 次
如果我們希望匹配特定的標記正好x次,我們可以新增{x}字尾。這在功能上等同於複製貼上該標記 x 次。
/a{3}/g
下面是匹配大寫的六個字元的十六進位制顏色程式碼的例子。
/#[0-9A-F]{6}/g
這裡,標記 {6} 應用於字符集 [0-9A-F]。
7.5 最小次和最大次之間
如果我們希望在最小次和最大次之間匹配一個特定標記,可以在這個標記後新增 {min,max} 。
/a{2,4}/g
警告 {min,max} 中逗號後面不要有空格。
7.6 最少 x 次
如果我們希望匹配一個特定的標記最少 x 次,可以在標記後新增 {x,}。 和 {min, max} 類似,只是沒有上限了。
/a{2,}/g
7.7 貪婪模式的注意事項
正規表示式預設使用貪婪模式。在貪婪模式下,會儘可能多的匹配符合要求的字元。
/a*/g
/".*"/g
在**重複運運算元(?,*,+,...)**後面新增 ? ,可以讓匹配變「懶」。
/".*?"/g
在這裡,這也可以透過使用 [^"] 代替。(這是最好的做法)。
/"[^"]*"/g
懶惰,意味著只要條件滿足,就立即停止;但貪婪意味著只有條件不再滿足才停止。 -Andrew S on StackOverflow
/<.+>/g
/<.+?>/g
7.8 例子
比特幣地址
/([13][a-km-zA-HJ-NP-Z0-9]{26,33})/g (思考: {26,33}?呢)
Youtube 影片
/(?:https?://)?(?:www.)?youtube.com/watch?.*?v=([^&s]+).*/gm
我們可以使用錨點調整表示式不讓它匹配最後一個不正確的連結,之後我們會接觸到。
8 交替
交替允許匹配幾個短語中的一個。這比僅限於單個字元的字元組更加強大。
使用管道符號 | 把多個短語之間分開
/foo|bar|baz/g
匹配 foo, bar, 和 baz 中的一個。
如果正則中只有一部分需要「交替」,可以使用組進行包裹,捕獲組和非捕獲組都可以。
/Try (foo|bar|baz)/g
Try 後面跟著 foo, bar, 和 baz 中的一個。
匹配 100-250 中間的數字:
/1dd|2[0-4]d|250/g
這個可以使用 Regex Numeric Range Generator 工具生成。
例子
十六進位制顏色
讓我們改進一下之前十六進位制顏色匹配的例子。
/#[0-9A-F]{6}|[0-9A-F]{3}
[0-9A-F]{6} 要放在 [0-9A-F]{3} 的前面,這一點非常重要。否則:
/#([0-9A-F]{3}|[0-9A-F]{6})/g
小提示 正規表示式引擎是從左邊到右邊的嘗試交替的。
羅馬數字
/^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/g
9 修飾符
修飾符允許我們把正規表示式分成不同的 "模式"。
修飾符是 /pattern/ 後面的部分。
不同引擎支援不同的修飾符。在這裡我們只討論最常見修飾符。
9.1 全域性修飾符(g)
到現在為止,所有的例子都設定了全域性修飾符。如果不啟用全域性修飾符,正規表示式匹配第一個以後將不再匹配其他任何字元。
/[aeiou]/g
/[aeiou]/
9.2 不區分大小寫修飾符(i)
顧名思義,啟用這個修飾符會使正則在匹配時不區分大小寫。
/#[0-9A-F]{6}/i
/#[0-9A-F]{6}/
/#[0-9A-Fa-f]{6}/
9.3 多行模式修飾符(m)
有限支援 在 Ruby 中,m 修飾符是執行其他的函式。
多行修飾符與正在在處理包含換行符的「多行」字串時對錨點的處理有關。預設情況下, /^foo$/ 只匹配 「foo」。
我們可能希望它在多行字串中的一行也能匹配 foo。
我們拿 "bar
foo
baz" 舉例子:
bar foo baz
如果沒有 m 修飾符,上面的字串會被當做單行 bar
foo
baz , 正規表示式 ^foo$ 匹配不到任何字元。
如果有 m 修飾符,上面的字串會被當做 3 行。 ^foo$ 可以匹配到中間那一行。
9.4 Dot-all修飾符 (s)
有限支援 ES2018 之前的 JavaScript 不支援這個修飾符。 Ruby 也不支援這個修飾,而是用 m 表示。
. 通常匹配除換行符以外的任何字元。使用dot all修飾符後,它也可以匹配換行符。
10 錨點
錨點本身不匹配任何東西。但是,他們會限制匹配出現的位置。
你可以把錨點當做是 "不可見的字元"。
10.1 行首 ^
在正則開始時插入 ^ 號,使正則其餘部分必須從字串開始的地方匹配。你可以把它當成始終要在字串開頭匹配一個不可見的字元。
/^p/g
10.2 行尾
在正則結尾時插入 $ 號, 類似於行首符。你可以把它當成始終要在字串結尾匹配一個不可見的字元。
/p$/g
^ 和 $ 錨點經常一起使用,以確保正則和字串整個匹配,而不僅僅是部分匹配。
/^p$/g
讓我們回顧一下重複中的一個例子,並在正則的末尾新增兩個錨點。
/^https?$/g
如果沒有這 2 個錨點, http/2 和 shttp 也會被匹配。
10.3 字邊界 
字邊界是一個字元和非詞字元之間的位置。
字邊界錨點  ,匹配字元和非詞字元之間存在的假想不可見字元。
/p/g
提示 字元包括 a-z , A-Z , 0-9 , 和 _ .
/p/g
/cat/g
還有一個非字邊界錨 B 。
顧名思義,它匹配除字邊界之外的所有內容。
/Bp/g
/BpB/g
小提示 ^…$ 和 … 是常見的模式,您幾乎總是需要這 2 個防止意外匹配。
10.4 例子
尾部空格
/s+$/gm
markdown 標題
/^## /gm
沒有錨點:
/## /gm
11 零寬斷言(lookaround)
零寬斷言可用於驗證條件,而不匹配任何文字。
你只能看,不能動。
先行斷言(lookhead) 正向 (?=…) 負向 (?!…)
先行斷言(lookbehind) 正向 (?<=…) 負向 (?<!…)
11.1 先行斷言(lookhead)
正向(positive)
/_(?=[aeiou])/g
注意後面的字元是如何不匹配的。可以透過正面前看得到證實。
/(.+)_(?=[aeiou])(?=1)/g
正則引擎在 _ 使用了 (?=[aeiou]) 和 (?=1) 進行檢查。
/(?=.*#).*/g
負向(Negative)
/_(?![aeiou])/g
/^(?!.*#).*$/g
如果沒有錨點,將匹配每個示例中沒有#的部分。
負向的先行斷言常常用於防止匹配特定短語。
/foo(?!bar)/g
/---(?:(?!---).)*---/g
11.2 例子
密碼驗證
/^(?=.*d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/
零寬斷言可用於驗證多個條件。
帶引號的字串
/(['"])(?:(?!1).)*1/g
如果沒有先行斷言,我們最多隻能做到這樣:
/(['"])[^'"]*1/g
12 進階例子
JavaScript 註釋
//*[sS]*?*/|//.*/g
[sS] 是一種匹配任何字元(包括換行符)的技巧。我們避免使用dot-all 修飾符,因為我們需要使用 . 表示單行註釋。
24小時時間
/^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/g
IP 地址
/(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]).){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))/g
元標籤
//gm
替換:
浮點數
可選符號
可選整數部分
可選小數部分
可選指數部分
/^([+-]?(?=.d|d)(?:d+)?(?:.?d*))(?:[eE]([+-]?d+))?$/g
正向的先行斷言 (?=.d|d) 確保不會匹配 ..
HSL顏色
從0到360的整數
/^0*(?:360|3[0-5]d|[12]?d?d)$/g
百分比
/^(?:100(?:.0+)?|d?d(?:.d+)?)%$/g
HSL 和 百分比
/^hsl(s*0*(?:360|3[0-5]d|[12]?d?d)s*(?:,s*0*(?:100(?:.0+)?|d?d(?:.d+)?)%s*){2})$/gi


[hongdian2012 ] 專門為初學者編寫的正規表示式入門教程已經有226次圍觀

http://coctec.com/docs/program/show-post-233780.html