前言
最近在重新學習正規表示式,把在學習過程中所遇到的案例,還有比較難理解概念用自己的理解分析並整理總結。
如有哪些地方不對,歡迎指正,謝謝!(๑•ᴗ•๑)
本系列使用的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
匹配的位置如下:
細心的你一定會發現數字的開始,小數點的左右都會有單詞邊界,這意味著單詞邊界不僅僅是英文字母,還包括數字。
\b
屬於匹配位置的元字元,一般作佔位作用,而不被捕獲,同屬於匹配位置的還有匹配行起始位^
和行結束位$
(4) 處理24小時制時間
24小時制可以分為三段:
- 00 - 09
- 10 - 19
- 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]/
- Try it: regexr.com/
- Regexp :
/[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複製程式碼
參考文獻:
- 《精通正規表示式》
- 《正規表示式經典例項》