本篇文章講述了JavaScript的Regex的基礎,大家對於JavaScriptRegex不熟悉的正好可以來學習學習,講的都是JavaScript比較基礎的Regex,不熟悉的同學我們一起來看看吧!
Regex學習(持續更新)
今天在學javascript的時候學到了RegExp對象,藉機學習一下Regex,以前沒接觸過,趁機學習一波,很舒服。
參考網站:Regex30分鐘入門教程點擊開啟連結
1.什麼是Regex
Regex是用來表述字串匹配的規則。
2.Regex的相關概念
2.1元字元
元字元是Regex中自己規定的一種特殊符號,在Regex中加入用以代替某些規則。
\b |
表示單詞的開始或結束 |
. |
表示除換行以外的任一字元 |
* |
表示*前面出現的任意個數的該字元,例如a*,表示前面有任意個數的a(重複0次或多次) |
+ |
表示+前面出現的任意個數的該字元,例如a+,表示前面有任意個數的a(重複1次或多次) |
? |
重複0或1次 |
{n} |
重複n次 |
{n, } |
重複大於等於n次 |
{n, m} |
重複n到m次 |
\w |
匹配字母或數字或底線或漢字 |
\s |
匹配任意的空白符,包括空格、定位字元、分行符號、中文全形空格等 |
3.簡單的Regex
直接從例子走起:
例1:當我想去匹配單詞hello時,所寫的Regex(匹配規則)為:hello
這樣會匹配到所有含有hello的單詞,如:helloworld也被匹配了進來,但如果只想匹配hello,則需要使用元字元\b,將hello前後斷開,形成單獨的單詞hello,則Regex應該為:\bhello\b
例2:當要找的hello後面任一字元處跟著一個world,則應當使用元字元.和*,Regex為\bhello\b.*\world\b
例3:當想去匹配021-xxxxxxx類似這樣的電話號碼時,應當使用021-\d\d\d\d\d\d\d,這其中“021-”為簡單的字元,不代表任何特殊含義,而後面使用的\d為元字元。這個Regex可簡寫為021-\d{7},代表\d重複了7次。
例4:匹配1個或多個連續數字,\d+
例5:匹配以a開頭的單詞,\ba\w*\b
例6:匹配5-12位的QQ號,^\d{5, 12}&
4.字元轉義
如果想要尋找的字串裡面有元字元,需要在元字元前面加上\來將元字元轉為普通的字元。
5.字元類
這部分解決的問題是如果想要匹配的字元沒有相應的元字元對應怎麼辦,那麼我們需要手動建立一個字元類。
例如如果數字0-9沒有\d與之匹配,那麼當我們想要尋找0-9的任一數字時,可以建立一個[0-9]的字元類,它的作用與\d完全相同。
例如Regex \(?0\d{2}[), -]?\d{8}可以用來匹配電話號碼,依次解釋一下\(代表對(進行轉義,?表示其重複0或1次,\d表示兩個數字,[), -]表示)和-的字元類,?表示其重複0或1次,後接著有8個數字。
6.分枝條件
上面寫的 \(?0\d{2}[), -]?\d{8}這樣的Regex可能會匹配到(01012345678或(010-12345678等不正確的字串,對於這樣的情況可以使用分枝條件,分枝條件與js中的邏輯或||類似,並且都是短路操作符,從左至右匹配到一個條件能判斷時就結束。
對於上面的情況可以寫為 \(0\d{2}\)\d{8}|0\d{2}-\d{8}|\(0\d{2}\)\d{8}
7.分組
該部分為瞭解決重複的不是單個字元,而是多個字元的問題。重複單個字元時我們可以使用字元+元字元裡面的限定符這樣的寫法,但當重複字元為多個時,可以在重複字元外加上()。例如下面的Regex可用來表示ip地址。
(2[0-4]\d|25[0-5]|[01]\d\d?\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
8.反義
當需要尋找不屬於某個能夠簡單定義的字元時,例如除了xxx以外的字元時,需要用到反義
\W |
匹配任意不是字母、數字、底線、漢字的字元 |
\D |
匹配任意不是數位字元 |
\B |
匹配任意不是單詞開頭或結束位置的字元 |
\S |
匹配任意不是空白的字元 |
[^x] |
匹配除了x以外的字元 |
[^aeiou] |
匹配除了aeiou之外的字元 |
例如Regex^\S+&用來匹配一段不含空白符的字元串
9.後向引用
這部分的內容跟前面的分組是匹配的,當我們使用()為字元分組後,這個分組我們可以通過編號的方式在後面繼續引用,對於通過()進行的分組,按照( 出現的順序從1開始進行分組,例如Regex\b(\w+)\s+\1\b,可以用來匹配重複出現的單詞,例如go go等,這裡就是通過\1引用了之前出現的分組。
其他涉及到的後向引用文法有:
(exp) |
匹配exp,並捕獲當前內容到自動的分組裡 |
(?<name>exp) |
匹配exp,並捕獲當前內容並分配組名為name |
(?:exp) |
匹配exp,不為捕獲的內容分配組名 |
10.零寬斷言
用於尋找在某部分內容之前或之後但不包括該內容的部分。
Regex(?=exp)的意思就是斷言後面出現的部分可以匹配運算式exp。比如\b\w+(?=ing\b),匹配以ing結尾的單詞的前面部分。比如尋找I'm dancing and singing時會匹配dance和sing(由於有\w+不會匹配為s)。
Regex(?<=exp)的意思是斷言前面的部分可以匹配運算式exp。比如(?<=\bre)\w+\b會匹配以re為開頭的單詞的後半部分,例如尋找reading時會匹配到ading。
假如你想給一個很長的數字每三位加一個逗號,例如對123456789加逗號,可以使用Regex((?<=\d)\d{3})+\b,尋找結果為234567890(這部分尋找規則沒看懂。。。)
下面的例子同時使用兩種斷言(?=<\s)\d+(?=\s),用來匹配兩個空白字元之間的數字,不包括空白字元。
總的來看,零寬斷言的目的就是為了按照一定的規則確定匹配字元的起始點或終止點。
11.負向零寬斷言
前面提到了使用反義來尋找不是某個字元或不在某個字元裡。
例如如果想尋找一個單詞出現了字母q而後面跟的不是u。可能會寫\bq[^u]\w*\b。但對於這樣的運算式,當q出現在單詞結尾時就會出現錯誤,因為[^u]會將單詞的間隔符匹配掉,這樣會進而匹配下一個單詞,它會匹配到Iraq fighting這樣的字串。
為瞭解決反義的佔用問題,我們可以使用負向零寬斷言,因為它只匹配一個位置,不會消耗掉任何字元。上面運算式的可以寫為\bq(?!u)\w*\b。
同理,我們用(?<!exp)來匹配前面不是exp的字元,如(?<![a-z])\d{7}來匹配前面不是小寫字母a-z的後面7個數字。
一個更複雜的例子:(?<=<(\w+)>).*(?=<\/\1>)
看到前面的(?<=)和後面的(?=),則知道前後都為零寬斷言,而<(\w+)>則代表html標記,如果前面的為<h>,則後面零寬斷言的意思是</h>(使用了轉義和後向引用)。所以這個Regex是為了匹配html標記之間的部分。
12.注釋
通過文法(?#comment)來包含注釋,例如2[0-4]\d(?#200-249)。
13.貪婪與懶惰
在處理字串匹配問題時,通常的行為是匹配儘可能多的字元。以運算式a.*b和字串aabab為例,會匹配aabab,而不是匹配ab,這樣的匹配規則稱為貪婪匹配。
而有時,我們需要匹配儘可能少字元的懶惰匹配,這時,需要在上面所說的限定符後面加上?,如a.*?b就將貪婪匹配轉化為懶惰匹配,此時會匹配到aab(1-3的字元)和ab(4-5的字元)(具體原因涉及到Regex的匹配規則)。
14.處理選項
類似於js裡面的flag,有不區別大小寫、多行模式、全域模式等。
15.平衡組/遞迴匹配
這部分為了處理匹配問題,例如想匹配數學運算式中(5*3)))中的(5*3),不能簡單的寫為\(.*\),這樣會匹配到整個運算式。那麼應當採取的匹配策略類似於學到過的括弧匹配問題,用棧來解決,遇到(壓棧,遇到)彈棧,如果最後棧為空白,這說明運算式裡面的括弧完全符合,如果不為空白,Regex引擎會回溯來使得括弧匹配。
相關推薦:
JS的Regex如何使用