正規表示式案例分析 (一)

琅琊丶發表於2017-07-11

前言

最近在重新學習正規表示式,把在學習過程中所遇到的案例,還有比較難理解概念用自己的理解分析並整理總結。

如有哪些地方不對,歡迎指正,謝謝!(๑•ᴗ•๑)

本系列使用的JavaScript所支援的正規表示式語法,並推薦你使用 regexr.com/ 去做相應的練習。

假定你已經熟悉元字元方括號修飾符,量詞RegExp物件

如果沒有,請先看一遍文件
www.w3school.com.cn/jsref/jsref…

本系列同步GitHub github.com/Janking/Blo…

案例分析

(1) 需要轉義的特殊字元

$ ( ) * + . ? [ \ ^ {

在文字中遇到 這幾種特殊字元想轉為文字,需要通過反斜槓\轉義:

/\$ \( \) \* \+ \. \? \[ \\ \^ \{/g

也許你會問到 -減號符,}右花括號,]右中括號為何不在內?首先減號符是在[]中的,在前面沒與到轉義的[左方括號時,減號符及右方括號-]是當普通文字處理,無需轉義,而花括號也如此

  • Try it: regexr.com/
  • Regexp : /\{\w+}\[hello-world]/
  • Text : {abc}[hello-world] hey! hey! hey!

(2) 再次匹配先前匹配的文字

如果需要匹配一個 yyyy-mm-dd 格式的日期,其中月份和日期都是年份的個十位

/\b\d\d(\d\d)-\1-\1\b/

反斜槓\1-9可以得到前面分組(\d\d)捕獲到的結果,如果是10-99呢?那就\10\99

  • Try it: regexr.com/
  • Regexp : /\b\d\d(\d\d)-\1-\1\b/
  • Text : 2008-08-08

(3) 單詞邊界

單詞邊界這個概念我開始比較抽象,也花了點時間去實踐到底是啥,所以在這裡作為一個案例來說說。

在單詞邊界匹配的位置,單詞字元後面或前面不與另一個單詞字元直接相鄰。 不太明白,還是看例項吧!

"That dang-tootin' #!@#$ varmint's cost me $199.95!".replace(/\b/g,function(){
 console.log(arguments)
});複製程式碼
//output
["", 0, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 4, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 5, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 9, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 10, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 16, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 24, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 31, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 32, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 33, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 34, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 38, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 39, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 41, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 43, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 46, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 47, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]
["", 49, "That dang-tootin' #!@#$ varmint's cost me $199.95!"]複製程式碼

通過控制檯輸出,我們可以發現\b匹配的位置如下:

https://user-gold-cdn.xitu.io/2017/7/11/3b6b20924441295026cd34c12e2a210a
https://user-gold-cdn.xitu.io/2017/7/11/3b6b20924441295026cd34c12e2a210a

細心的你一定會發現數字的開始,小數點的左右都會有單詞邊界,這意味著單詞邊界不僅僅是英文字母,還包括數字。

\b屬於匹配位置的元字元,一般作佔位作用,而不被捕獲,同屬於匹配位置的還有匹配行起始位^和行結束位$

(4) 處理24小時制時間

24小時制可以分為三段:

  1. 00 - 09
  2. 10 - 19
  3. 20 - 23

先匹配第一階段: /[0][0-9]/

再接著匹配第二階段:/[01][0-9]/

第三階段以此類推?/[012][0-9]/

明顯不合適,因為不可能出現大於23以上的數字,那麼只能開分支了 /[01][0-9]|2[0-3]/

也許你會說,00-09如果要匹配“沒有補零”的情況呢?(即:0,1,2,3,4,5...)

我們可以藉助一下量詞?匹配 /[01]?[0-9]|2[0-3]/

(5) 千分位

我們在一些場景裡需要將7654321輸出成7,654,321這樣的格式,這就是千分位,用正規表示式去處理的話,關鍵是獲取位置,那麼首先想到的就是要利用非單詞邊界\B,下面這條正則是能成功取得千分位的位置的:

/\B(?=(\d{3})+(?!\d))/g

先將這個正則分解成三部分:

1 )、 /\B(?=\d)/ 這是\B是為了防止出現,123起始位置被匹配的問題,(?=\d)是非單詞邊界後緊跟數字

2 )、 嘗試一下8位數的數字: '12345678' 在 /\B(?=(\d{3})+)/匹配得到什麼結果呢?

// input
'12345678'.replace(/\B(?=(\d{3})+)/g,function(){console.log(arguments);return '|'})複製程式碼
// output
["", "567", 1, "12345678"]
["", "678", 2, "12345678"]
["", "456", 3, "12345678"]
["", "567", 4, "12345678"]
["", "678", 5, "12345678"]

"1|2|3|4|5|678"複製程式碼

首先符合非單詞邊界\B的有1,2,3,4,5,6,7的右邊位置,而後面也同樣緊跟數字2,3,4,5,6,7

其次符合\d{3}的有234,345,456,567,678,但後面跟個加號+結果就不一樣了

那為什麼會得到567,678,456,567,678,這樣奇怪的匹配?原理如下:

1. 匹配`\B`第1個非單詞邊界 `1`的右邊位置,則後面(\d{3})+的結果為:234、567,8後面無法補齊3位,匹配得到567
2. 匹配`\B`第2個非單詞邊界 `2`的右邊位置,則後面(\d{3})+的結果為:345、678,匹配得到678
3. 匹配`\B`第3個非單詞邊界 `3`的右邊位置,則後面(\d{3})+的結果為:456、78後面無法補齊3位,匹配得到456
4. 匹配`\B`第4個非單詞邊界 `4`的右邊位置,則後面(\d{3})+的結果為:567、8後面無法補齊3位,匹配得到567
5. 匹配`\B`第5個非單詞邊界 `5`的右邊位置,則後面(\d{3})+的結果為:678
6. 匹配`\B`第6個非單詞邊界 `6`的右邊位置,但78無法補齊3位,
7. 同6
8. 最終小括號分組匹配得到的分別是:567,678,456,567,678複製程式碼

3 )、最後 (?!\d) 是前面匹配成功後跟的非數字,那連起來就是:

1. 匹配`\B`第1個非單詞邊界 `1`的右邊位置,則後面(\d{3})+的結果為:234、567,後面跟著8,不匹配
2. 匹配`\B`第2個非單詞邊界 `2`的右邊位置,則後面(\d{3})+的結果為:345、678,後面跟著非數字,位置匹配成功
3. 匹配`\B`第3個非單詞邊界 `3`的右邊位置,則後面(\d{3})+的結果為:456,後面跟著7、8不匹配
4. 匹配`\B`第4個非單詞邊界 `4`的右邊位置,則後面(\d{3})+的結果為:567,後面跟著8,不匹配
5. 匹配`\B`第5個非單詞邊界 `5`的右邊位置,則後面(\d{3})+的結果為:678,後面跟著非數字,位置匹配成功
6. 最終得到得到可插入逗號的位置為2,5複製程式碼

參考文獻:

  • 《精通正規表示式》
  • 《正規表示式經典例項》

相關文章