日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

正則表達式從小白到入門

 

前言

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


為什么要正則表達式?

為什么需要正則表達式 - 王垠

學習 Unix 最開頭,大家都學過正則表達式 (regexp)。可是有沒有人考慮過我們為什么需要正則表達式?

正則表達式本來的初衷是用來從無結構的字符串中提取信息,殊不知這正好是 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? 可以匹配 harttl 和 harttle。
  4. 組合(括號,())。組合用來定義操作符的作用范圍和優先級。例如 har(ttle)? 可以匹配 harttle 和 har,h(a|u)rttle 可以匹配 harttle 和 hurttle。

常用正則表達式

字符 描述 \ 將下一個字符標記為一個特殊字符、或一個原義字符、或一個向后引用、或一個八進制轉義符。例如,”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 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,”erb“可以匹配”never“中的”er“,但不能匹配”verb“中的”er“。 B 匹配非單詞邊界。”erB“能匹配”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 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ fnrtv]。 S 匹配任何非空白字符。等價于 [^ fnrtv]。 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

分享到:
標簽:正則表達式
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定