正則表達式詳解

正則表達式是一個非常有用的用來匹配驗證字符串的工具。很多人覺得正則表達式規則繁多,學了也會忘記,不如等到需要使用的時候再去查閱即可。這樣的觀點也無可厚非,不過我曾經看到過一個絕妙的關於閱讀的比喻,閱讀就像是將竹簍浸入到水裏面,雖然撈打上來的時候竹簍裏並沒有裝水,但是竹簍已經被浸溼了。學習正則表達式也是如此,循序漸進,方能厚積薄發。

大綱

◆ 常用的正則表達式

◆ 分組捕獲與後向引用

◆ 貪婪模式與非貪婪模式

◆ 應用場景

常用的正則表達式

1.元字符

元字符 釋義
普通字符 如A-Z、a-z、0-9 等等
. 除換行以外的其他任意字符, 如果需要匹配換行符,可用[.n]
s 空白字符
S 除空白字符以外的任意字符
w 字母、數字、下劃線
W 除了字母、數字、下劃線以外的任意字符
d 數字 0-9
D 除了數字之外的任意字符
^ 匹配輸入字符串開始的位置
$ 匹配輸入字符串結尾的位置
b 單詞邊界,匹配一個完整的單詞可以使用 bwordb

以上是最常用的正則表達式匹配字符,當然,還有很多其他的匹配元字符,比如\t匹配製表符,\r匹配回車符,\n匹配換行符等。

\d爲例,\d代表數字0-9,等價於字符組[0-9]

例:匹配字符串 ‘fefafe332gt66ooj44nie85kk’ 中的所有數字
var str = 'fefafe332gt66ooj44nie85kk'
var reg = /\d+/g
console.log(str.match(reg)) // 結果未["332", "66", "44", "85"]

2.限定符

限定符 釋義
  • | 0到無數次。例如,zo* 能匹配 "z" 以及 "zoo"
  • | 1到無數次。例如,zo+ 不能匹配 “z” 但是能匹配 “zo”和“zoo”

? | 0 或者1 次。例如,zo? 能匹配 “z”和 “zo” 但是不能匹配 “zoo”
{n} | 匹配確定的N次。 例如, zo{2} 只能匹配到 zoo
{n,} | 匹配n到無限次。 例如,zo{1,} 不能匹配“z” 但是能匹配“zo”和“zoo”
{n,m} | 匹配n到m次。注意:在逗號和兩個數之間不能有空格

以上這些限定符,可以匹配指定個數的字符,在能夠匹配的範圍之內,儘可能多的匹配。其中{n,m}限定符有兩個注意點:

  1. n不能大於m
  2. 在逗號和兩個數之間不能有空格,否則無法匹配
例:匹配38到288之間的數
let reg = /\b((38|39)|([4-9]\d)|(1\d{2})|(2[0-7]\d)|(28[0-8]))\b/g
let str = '45 454 255 288 38 88 11 37 100 109 28 000 289 209'
console.log(str.match(reg)) // ["45", "255", "288", "38", "88", "100", "109", "209"]

3.修飾符

修飾符 釋義
g global 全局搜索 (不添加 搜索到第一個匹配停止)
i ignore case 忽略大小寫
m multiline 多行匹配

m多行匹配用得相對較少,但是也有一定用處。

例:對比m和mg
var str8 = "abeifenabc\nabpheeabc" 
var reg8a = /^ab/gm
var reg8b = /^ab/g
console.log(str8.match('gm:'+reg8a)) // 結果爲:["ab", "ab"]
console.log(str8.match('g:'+reg8b)) // 結果爲:["ab"]

上面三個修飾符最常用。當然,還有其他修飾符,比如A表示強制從目標字符串開頭匹配,x表示將模式中的空白忽略。

4.其他

常用符號 釋義
分支符號"\ " 用來匹配指定幾個規則中的一個
轉義符號"\" 用於匹配"[""^""+"")"等有特殊含義符號
字符組 [] 用於匹配指定範圍之內的任意一個字符

例如:表達式 [cChH]at 可以只能匹配到 catCathatHat 四個字符串中的一個

例:敏感詞過濾。比如:“我草你媽哈哈背景天胡景濤哪肉涯剪短髮慾望”,過濾:'草肉慾胡景濤'
let str9 = '我草你媽哈哈背景天胡景濤哪肉涯剪短髮慾望';
let regExp = /草|肉|欲|胡景濤/g;
let result = str9.replace(regExp, function(match) {
    let len = match.length;
    let str;
    switch (len) {
        case 1:
            str = '*';
            break;
        case 2:
            str = "**";
            break;
        case 3:
            str = "***";
            break;
        default:
            str = '****';
    }
    return str;
});
console.log(result); //我*你媽哈哈背景天***哪*涯剪短髮*望

分組捕獲與後向引用

1.分組捕獲

當我們想要匹配多個字符的時候,可以使用限定符來指定個數,那當我們需要匹配多個字符串的情況,該怎麼辦呢?可以使用分組捕獲

  • 概念:

分組捕獲是指將想要匹配的正則表達式用小括號括起來,然後與限定符組合使用,可以連續匹配符合規則的字符串。每一個小括號代表的表達式分爲一組,作爲子表達式,後期可以通過捕獲不同組的內容來進行替換等操作。

例:匹配字符串isuwang連續出現3次的情況

isuwang{3} isuwang1

(isuwang){3} isuwang2

可以看到,下面一組例子將isuwang字符串當作一個組,整體匹配了3次。

2.非捕獲分組

  • 分組捕獲的缺點:

有些不得不用()但是後期又不會用到的子表達式內容,記錄在組裏面會佔用內存,降低匹配效率

  • 解決:

使用非捕獲組。只進行分組,並不將子表達式匹配到的內容捕獲到組裏。

字符 描述 示例
(?:pattern) 匹配pattern,但不捕獲匹配結果。 ‘industr(?:y\ ies)匹配'industry'或'industries'
(?=pattern) 零寬度正向預查,不捕獲匹配結果。 'Windows (?=95\ 98\ NT\ 2000)'匹配 "Windows2000" 中的 "Windows",不匹配 "Windows3.1" 中的 "Windows"。
(?!pattern) 零寬度負向預查,不捕獲匹配結果。 'Windows (?!95\ 98\ NT\ 2000)'匹配 "Windows3.1" 中的 "Windows"不匹配 "Windows2000" 中的 "Windows"。
(?<=pattern) 零寬度正向回查,不捕獲匹配結果。 '2000 (?<=Office\ Word\ Excel)'匹配 " Office2000" 中的 "2000",不匹配 "Windows2000" 中的 "2000"。
(?<!pattern) 零寬度負向回查,不捕獲匹配結果。 '2000 (?<!Office\ Word\ Excel)'匹配 " Windows2000" 中的 "2000",不匹配 " Office2000" 中的 "2000"。
  • 使用情況:

一般只有在比較複雜,“()”使用較多的情況下會考慮使用非捕獲組。比如驗證日期的正則表達式。

  • 對比:

未使用非捕獲組的正則

^((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)$

使用了非捕獲組的正則:

^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$

3.後向引用

  • 作用:

後向引用用於重複搜索前面某個分組匹配的文本。例如,\1 代表分組1匹配的文本,也可以用$1來表示

  • 說明:

子分組捕獲的內容可在正則表達式裏面或者其他文本里面作進一步的處理。默認情況下,從左向右,以分組的左括號爲標誌,第一個出現的分組的組號爲1,第二個爲2,以此類推。也可以使用命名分組的方式,對每個分組進行命名。

例:檢查重複字符串\
給定字符串 str,檢查其是否包含連續重複的字母(a-zA-Z),包含返回 true,否則返回false
let str4 = 'abccdefgjhiss'
let reg4a = /([a-zA-Z])\1/g
let reg4b = /([a-zA-Z]){2}/g
console.log(str4.match(reg4a)) // ["cc", "ss"]
console.log(str4.match(reg4b)) // ["ab", "cc", "de", "fg", "jh", "is"]

4.貪婪模式和非貪婪模式

  • 貪婪模式:

在整個表達式匹配成功的前提下,儘可能多的匹配

  • 非貪婪模式:

整個表達式匹配成功的前提下,儘可能少的匹配。非貪婪模式只被部分NFA引擎所支持。

  • 量詞:
貪婪模式 非貪婪模式
{m,n} {m,n}?
{m,} {m,}?
? ??
* *?
+ +?
例子:
提取兩個""中的子串,其中不能再包含""\
字符串:"The colleagues in "kuaisuwang" are very "diligent" and united"

錯誤解法(通過非貪婪匹配)

let str6='"The colleagues in "isuwang" are very "diligent" and united"'
let reg6a=/".*?" /g // 注意"後面還有個空格
console.log(str6.match(reg6a)) //  [""The colleagues in "isuwang" ", ""diligent" "]

正確解法(通過貪婪模式匹配)

let str6='"The colleagues in "isuwang" are very "diligent" and united"'
let reg6b=/"[^"]*" /g // 注意"後面還有個空格
console.log(str6.match(reg6b)) //[""isuwang" ", ""diligent" "]

總結

此篇文章主要講述了常用的正則表達式符號,以及分組和後向引用,貪婪模式和非貪婪模式兩種模式,這些知識點呢,在工作當中會非常有用。至於正則表達式在我工作中的運用,我放在下一篇來跟大家進行分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章