正則表達式從小白到入門

前言

正則表達式(Regular Expression,RegExp,regex)使用單個字符串來描述和匹配一系列符合某種句法規則的字符串。此概念來自形式化語言理論,最初由貝爾實驗室實現。正則表達式最初在 Perl 中實現,它的推廣得益於 UNIX 軟件的流行,尤爲是 SED,GREP 等。 如今許多編程語言都內置了正則表達式引擎,如 PERL、Python、JavaScript、Java、C++ 等。不少文本編輯器也支持正則表達式來進行檢索和替換,如 Vim、Sublime Text、Visual Studio Code 等。正則表達式相關的學習文章網上也是一大推,本文主要記錄正則表達式的入門教程和經常使用公式工具,方便你們活學活用。html

正則表達式從小白到入門

更新歷史

2019年09月12日 - 初稿python

閱讀原文 - https://wsgzao.github.io/post...git

擴展閱讀github

正則表達式 30 分鐘入門教程 - https://deerchao.net/tutorial...web


爲何要正則表達式?

爲何須要正則表達式 - 王垠正則表達式

學習 Unix 最開頭,你們都學過正則表達式 (regexp)。但是有沒有人考慮過咱們爲何須要正則表達式?express

正則表達式原本的初衷是用來從無結構的字符串中提取信息,卻不知這正好是 Unix 的缺陷所在。Unix 用無結構的字符串來表示數據,致使了諸多複雜的基於 regexp 的軟件的誕生。sed, AWK, Perl, … 都是爲了一樣的目的來到這個世界上的。若是不是由於 Unix 用字符串來表示數據,咱們就會擁有按數據結構類型的直接存儲,而不須要折騰 regexp。正則表達式有它本身的價值(針對天然語言),可是咱們其實不須要把它應用到程序語言和操做系統裏面。編程

正則表達式自己用一個字符串來表示,這帶來另一些問題。由於正則表達式的本質不是字符串,而是一個數據結構。學過計算理論的人可能知道這個數據結構叫作 NFA(nondeterministic finite automaton,非肯定性有限自動機)。全部的數據結構應該由程序語言自己來表示,就像用 Java 構造一個對象用 new ClassA("a") 同樣。可是正則表達式強迫你把這個簡單的構造函數調用寫成一個字符串。因此在這個比方之下,你得寫成 new ClassA(\"a\")。這樣當你想要組合這些表達式的時候就發現,正則表達式幾乎都是不可組合 (compose) 的。你幾乎不可能不能把兩個 regexp 的變量 A 和 B 安全拼接成一個,好比用 Java 的字符串拼接 A+B。由於你不知道這兩個字符串拼在一塊兒以後,那些稀奇古怪的符號會出現什麼交叉反應,使得最後的識別的東西根本不是你想要的。安全

在正則表達式中,因爲正則表達式自己的構造函數與數據自己合併到一塊兒,咱們不得不對某些 「特殊字符」 進行 escape。這些特殊字符,實際上是用來描述 NFA 的記號,它們屬於更高一層的語言。但是在正則表達式裏,它們與 NFA 節點裏的字符混爲一談。好比很簡單的一個 block comment 的正則表達式,卻要寫成這個樣子:數據結構

/\\\\\*(\[^\\\\\*\]|\[^/\])\*\\\\\*/

顯然這樣的表達式很容易出錯。 若是咱們用程序語言的表達式來構造這個表達式,它應該是這樣:

(@... "/\*" (@\*(@!"\*/")) "\*/")

在這個我本身設計的 Scheme 表達式裏,以 @開頭的標識符都是構造函數。其中 @... 是構造 sequence,@* 是構造一個 zero-or-more 的匹配,@! 構造一個否認匹配。這個表達式是說:「以 / * 開頭,接着零個或者多個不是 * / 的字符,最後接着一個 * /。這樣一來清晰明瞭,什麼表達式在什麼 「層次」 都很清楚,不須要什麼反斜槓 escape,並且這樣的表達式能夠 compose。好比:

(define reg1 (@... "/\*" (@\*(@!"\*/")) "\*/"))
(define reg2 (@+ "foo"))
(define reg3 (@= "b"))

定義這三個表達式以後,咱們以後能夠用像 (@... reg1 (@or reg2 reg3)) 這樣的表達式來鏈接 3 個不一樣的表達式,構造出更大的表達式。這樣的構造能夠無限的擴展。從這裏以及以往的經驗,我總結出一個廣泛適用的程序設計的教訓:儘可能不要把多個層次的語言 「壓縮」 到一層。咱們也看到正則表達式與 「Unix 哲學」 有很大關係。我沒有考古,因此不知道孰先孰後,可是它們確定有直接的因果關係。二者都是 Unix 複雜性的來源。

再來看取自 12306 網站的一段代碼
// http://www.12306.cn/mormhweb/js/adKyfw.min.js
d = d.replace("'", "");
d = d.replace("%", "");
d = d.replace("#", "");
d = d.replace("&", "");
d = d.replace("*", "");
d = d.replace("(", "");
d = d.replace(")", "");
d = d.replace("@", "");
d = d.replace("`", "");
d = d.replace("/", "");
d = d.replace("\\", "");
d = d.replace(",", "");
d = d.replace(".", "");
d = d.replace("=", "");
d = d.replace("<", "");
d = d.replace(">", "");

上述代碼是在過濾掉不合法的搜索字符(姑且不論客戶端過濾是否安全), 咱們能夠用一行正則替換來實現相同的功能:

d = d.replace(/'%#\&\*\(\)@`\/\\,\.=<>/g, '');

正則表達式入門教程推薦

感謝做者deerchao從2006年開始更新至今,謝謝

正則表達式 30 分鐘入門教程 - DeerChao

正則表達式 - 教程

Python RegEx

正則表達式在線工具

regexr

regex101

正則表達式測試工具(在線)

正則表達式在線測試

正則表達式基本語法

定義正則表達式的方式在不一樣的工具中可能有所差異,但正則表達式內容的語法是一致的。 正則表達式有三類語法結構:

  1. 串接(與操做)。相鄰的字符默認爲串接關係。例如 harttle 只能匹配 harttle, 不可匹配 hart
  2. 選擇(或操做,|)。例如:harttle|serene 能夠匹配 harttle 或者 serene。 選擇的優先級級低於串接,所以不少狀況下均可以省略括號。
  3. 數量(限定符)。最多見的數量限定符包括 +, ?, *,分別表示左側的字符出現一次或更多,不出現或出現一次,不出現或出現任意次。例如 harttle? 能夠匹配 harttlharttle
  4. 組合(括號,())。組合用來定義操做符的做用範圍和優先級。例如 har(ttle)? 能夠匹配 harttleharh(a|u)rttle 能夠匹配 harttlehurttle

經常使用正則表達式

字符 描述
\\ 將下一個字符標記爲一個特殊字符、或一個原義字符、或一個向後引用、或一個八進制轉義符。例如,」n「匹配字符」n「。」\n「匹配一個換行符。序列」\「匹配」\「而」 (「則匹配」(「。
^ 匹配輸入字符串的開始位置。若是設置了 RegExp 對象的 Multiline 屬性,^ 也匹配」\n「或」\r「以後的位置。
$ 匹配輸入字符串的結束位置。若是設置了 RegExp 對象的 Multiline 屬性,$ 也匹配」\n「或」\r「以前的位置。
* 匹配前面的子表達式零次或屢次。例如,zo 能匹配」z「、」zo「以及」zoo「。等價於 {0,}。
+ 匹配前面的子表達式一次或屢次。例如,」zo+「能匹配」zo「以及」zoo「,但不能匹配」z「。+ 等價於 {1,}。
? 匹配前面的子表達式零次或一次。例如,」do(es)?「能夠匹配」do「或」does「中的」do「。? 等價於 {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?「。請注意在逗號和兩個數之間不能有空格。
? 當該字符緊跟在任何一個其餘限制符(*,+,?,{n},{n,},{n,m})後面時,匹配模式是非貪婪的。非貪婪模式儘量少的匹配所搜索的字符串,而默認的貪婪模式則儘量多的匹配所搜索的字符串。例如,對於字符串」oooo「,」o+?「將匹配單個」o「,而」 o+「將匹配全部」o「。
. 匹配除」\n「以外的任何單個字符。要匹配包括」\n「在內的任何字符,請使用像」 (.|n) 「的模式。
(pattern) 匹配 pattern 並獲取這一匹配的子字符串。該子字符串用於向後引用。所獲取的匹配能夠從產生的 Matches 集合獲得,在 VBScript 中使用 SubMatches 集合,在 JScript 中則使用 $0...$9 屬性。要匹配圓括號字符,請使用」(「或」)「。
(?:pattern) 匹配 pattern 但不獲取匹配的子字符串,也就是說這是一個非獲取匹配,不存儲匹配的子字符串用於向後引用。這在使用或字符」(|)「來組合一個模式的各個部分是頗有用。例如」industr(?:y|ies)「就是一個比」industry|industries「更簡略的表達式。
(?=pattern) 正向確定預查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供之後使用。例如,」Windows(?=95|98|NT|2000)「能匹配」Windows2000「中的」Windows「,但不能匹配」 Windows3.1「中的」Windows「。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配以後當即開始下一次匹配的搜索,而不是從包含預查的字符以後開始。
(?!pattern) 正向否認預查,在任何不匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供之後使用。例如」Windows(?!95|98|NT|2000)「能匹配」Windows3.1「中的」Windows「,但不能匹配」 Windows2000「中的」Windows「。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配以後當即開始下一次匹配的搜索,而不是從包含預查的字符以後開始
(?<=pattern) 反向確定預查,與正向確定預查相似,只是方向相反。例如,」(?<=95|98|NT|2000)Windows「能匹配」2000Windows「中的」Windows「,但不能匹配」3.1Windows「中的」 Windows「。
(?<!pattern) 反向否認預查,與正向否認預查相似,只是方向相反。例如」(?<!95|98|NT|2000)Windows「能匹配」3.1Windows「中的」Windows「,但不能匹配」2000Windows「中的」 Windows「。
x|y 匹配 x 或 y。例如,」z|food「能匹配」z「或」food「。」(z|f)ood「則匹配」zood「或」 food「。
[xyz] 字符集合(character class)。匹配所包含的任意一個字符。例如,」[abc]「能夠匹配」plain「中的」a「。特殊字符僅有反斜線 \\ 保持特殊含義,用於轉義字符。其它特殊字符如星號、加號、各類括號等均做爲普通字符。脫字符 ^ 若是出如今首位則表示負值字符集合;若是出如今字符串中間就僅做爲普通字符。連字符 - 若是出如今字符串中間表示字符範圍描述;若是若是出如今首位則僅做爲普通字符。
[^xyz] 排除型(negate)字符集合。匹配未列出的任意字符。例如,」[^abc]「能夠匹配」plain「中的」plin「。
[a-z] 字符範圍。匹配指定範圍內的任意字符。例如,」[a-z]「能夠匹配」a「到」z「範圍內的任意小寫字母字符。
[^a-z] 排除型的字符範圍。匹配任何不在指定範圍內的任意字符。例如,」[^a-z]「能夠匹配任何不在」a「到」z「範圍內的任意字符。
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,」er\b「能夠匹配」never「中的」er「,但不能匹配」verb「中的」er「。
\B 匹配非單詞邊界。」er\B「能匹配」verb「中的」er「,但不能匹配」never「中的」er「。
\cx 匹配由 x 指明的控制字符。例如,\cM 匹配一個 Control-M 或回車符。x 的值必須爲 A-Z 或 a-z 之一。不然,將 c 視爲一個原義的」c「字符。
\d 匹配一個數字字符。等價於 [0-9]
\D 匹配一個非數字字符。等價於 [^0-9]
\f 匹配一個換頁符。等價於 \x0c\cL
\n 匹配一個換行符。等價於 \x0a\cJ
\r 匹配一個回車符。等價於 \x0d\cM
\s 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]
\S 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]
\t 匹配一個製表符。等價於 \x09\cI
\v 匹配一個垂直製表符。等價於 \x0b\cK
\w 匹配包括下劃線的任何單詞字符。等價於」[A-Za-z0-9]「。
\W 匹配任何非單詞字符。等價於」[^A-Za-z0-9]「。
\xn 匹配 n,其中 n 爲十六進制轉義值。十六進制轉義值必須爲肯定的兩個數字長。例如,」\x41「匹配」A「。」\x041「則等價於」\x04&1「。正則表達式中可使用 ASCII 編碼。.
\num 向後引用(back-reference)一個子字符串(substring),該子字符串與正則表達式的第 num 個用括號圍起來的子表達式(subexpression)匹配。其中 num 是從 1 開始的正整數,其上限多是 99。例如:」(.)\1「匹配兩個連續的相同字符。
\n 標識一個八進制轉義值或一個向後引用。若是 \n 以前至少 n 個獲取的子表達式,則 n 爲向後引用。不然,若是 n 爲八進制數字(0-7),則 n 爲一個八進制轉義值。
\nm 標識一個八進制轉義值或一個向後引用。若是 \nm 以前至少有 nm 個得到子表達式,則 nm 爲向後引用。若是 \nm 以前至少有 n 個獲取,則 n 爲一個後跟文字 m 的向後引用。若是前面的條件都不知足,若 n 和 m 均爲八進制數字(0-7),則 \nm 將匹配八進制轉義值 nm。
\nml 若是 n 爲八進制數字(0-3),且 m 和 l 均爲八進制數字(0-7),則匹配八進制轉義值 nml。
\un 匹配 n,其中 n 是一個用四個十六進制數字表示的 Unicode 字符。例如,\u00A9 匹配版權符號(©)。

參考文章

Wikipedia 正則表達式

MDN RegExp

正則表達式 30 分鐘入門教程 - DeerChao

相關文章
相關標籤/搜索