前端正則表示式學習和實踐
最近的專案裡有多處格式和查詢使用到了正則表達。簡單的正則語法會寫了,但是一直沒有花功夫研究遇到的複雜正則。剛好趁著這一波研究的興趣,總結一下自己學習到的東西,不再沒有靈魂的 google 後複製貼上了。以後再看別人寫的優雅程式碼,再也不用眼饞了。
推薦工具
regexper的解析真的非常有用處,它可以圖形化的展示出一個正則的所有的邏輯分支。對於自己難以讀懂的長正則,或者自己寫的複雜正則,都可以先解析成圖形化的邏輯來分析,大大降低了難度。如下圖隨便寫的一個正則解析:

正則表示式基礎知識
字元類
字元 | 匹配 | 字元 | 匹配 |
---|---|---|---|
[] | 方括號內的任何字元 | [^] | 不在方括號內的任何字元 |
\w | [a-zA-Z0-9] | \W | [^a-zA-Z0-9] |
\s | 任何Unicode空白字元 | \S | 任何Unicode空白字元 |
\d | [0-9] | \D | [^0-9] |
. | 除了換行符和其它Unicode終止符之外的任意字元 | \b | 單詞的邊界。\w和\W之間的邊界。 |
重複
字元 | 含義 |
---|---|
{n,m} | n <= matches < m |
{n,} | matches >= n |
{n} | matches === n |
? | {0,1} |
+ | {1,} |
* | {0,} |
注意:
*
和 ?
可以匹配0個字元,因此它們允許什麼都不匹配。
/a*/.test('bbbb')//=> true 複製程式碼
非貪婪重複
正常匹配重複字元是儘可能多的匹配,我們稱之為“貪婪的”匹配。
非貪婪的匹配級儘可能的少匹配。只需在待匹配字元後加一個問號
// 貪婪匹配 'bbbb'.match(/b+/g)// => ["bbbb"] // 非貪婪匹配 'bbbb'.match(/b+?/g)// => ["b", "b", "b", "b"] 複製程式碼
正則表示式匹配總是會尋找字串中第一個可能匹配的位置。因此不會考慮它子串中更短的匹配。
'aaab'.match(/a+b/g)// => ["aaab"] // 你可能想得到 ’ab‘, 但是並不會。 'aaab'.match(/a+?b/g)// => ["aaab"] 複製程式碼
選擇
字元 | 含義 |
---|---|
| | 或關係 |
引用
字元 | 含義 |
---|---|
() | 1. 把單獨的項合成子表示式,以便像處理一個獨立單元那樣使用。 |
2. 在完整模式中定義子模式。當一個正則表示式成功和目標字串匹配時,可以從目標串中抽出子模式匹配的部分。 | |
3. 允許在同一個正則表示式的後面引用前面的子表示式。 \1 引用的是第一個帶圓括號的子表示式。 \3 引用的是第三個。因為可以巢狀,所以是按參與計數的左括號的位置來決定。 |
|
\n | 和第 n 個分組匹配的字串匹配 |
引用的一個好處就是並不是子表示式相同,而是與引用子表示式模式匹配的文字相等。即一個字串中各個部分包含的是完全相同的字串。
例如匹配單引號或雙引號:
// 它並不要求左右 單雙引號 是匹配的 const partten = /['"][^'"]*['"]/g // 改為 const partten = /(['"])[^'"]*\1/g 複製程式碼
分組
字元 | 含義 |
---|---|
() | 可以記住和這個組合匹配的字串以供以後的引用使用 |
(?:) | 單純分組,不記住與該組合匹配的字串 |
錨點
類似 \b不匹配任何字元,指定匹配發生的合法位置。有時我們成為正則表示式的錨。
字元 | 含義 |
---|---|
\b | 單詞邊界(a word boundary),\w和\W之間的邊界,或位於一個單詞與字串開始和結束之間的邊界。 |
\B | 非單詞邊界(Non-word boundary) |
^ | 字串的開始 |
$ | 字串的結束 |
前後關聯約束
字元 | 含義 |
---|---|
(?=) | 前置約束-存在 |
(?!) | 前置約束-排除 |
(?<=) | 後置約束-存在 |
(?<!) | 後置約束-排除 |
修飾符
字元 | 含義 |
---|---|
i | 執行不區分大小寫 |
g | 找到所有匹配,否則在找到第一個後就停止 |
m | 多行匹配,^匹配一行的開頭,$匹配一行的結束 |
JavaScript基礎知識
用於模式匹配的 string 方法
String.prototype.search()
返回第一個滿足條件的匹配結果在整個字串中的位置。如果沒有任何匹配,則返回-1。
注意: 不支援全域性搜尋。只返回第一個匹配的位置資訊。
"This is a test text".search(/th/i)// => 0 複製程式碼
String.prototype.replace()
字串物件的replace方法可以替換匹配的值。它接受兩個引數,第一個是正則表示式,表示搜尋模式,第二個是替換的內容。
var str = '#id div.class'; str.replace(/^\s+|\s+$/g, '') // "#id div.class" 複製程式碼
replace方法的第二個引數可以使用美元符號$,用來指代所替換的內容。
符號 | 含義 |
---|---|
$& | 匹配的子字串 |
$` | 匹配結果前面的文字 |
$’ | 匹配結果後面的文字 |
$n | 匹配成功的第n組內容,n從1開始。 |
$$ | 指代美元 $ |
replace方法的第二個引數還可以是一個函式,將每一個匹配內容替換為函式返回值。
var a = 'The quick brown fox jumped over the lazy dog.'; a.replace(pattern, function replacer(match) { return match.toUpperCase(); }); 複製程式碼
String.prototype.match()
返回匹配的陣列或null。 g 修飾符有效。
String.prototype.split()
str.split(separator, [limit]) 複製程式碼
RegExp物件
RegExp.prototype.test()
返回布林型別
如果正則表示式帶有 g
修飾符,則每一次 test
方法都從上一次結束的位置開始向後匹配。
帶有 g
修飾符時,可以通過正則物件的 lastIndex
屬性指定開始搜尋的位置。
var r = /x/g; var s = '_x_x'; r.lastIndex = 4; r.test(s) // false 複製程式碼
如果正則模式是一個空字串,則匹配所有字串。
RegExp.prototype.exec()
正則例項物件的 exec
方法,用來返回匹配結果。如果發現匹配,就返回一個數組,成員是匹配成功的子字串,否則返回 null
。
var s = '_x_x'; var r1 = /x/; var r2 = /y/; r1.exec(s) // ["x"] r2.exec(s) // null 複製程式碼
如果正則表示式包含圓括號(即含有“組匹配”),則返回的陣列會包括多個成員。第一個成員是整個匹配成功的結果,後面的成員就是圓括號對應的匹配成功的組。也就是說,第二個成員對應第一個括號,第三個成員對應第二個括號,以此類推。整個陣列的 length
屬性等於組匹配的數量再加1。
var s = '_x_x'; var r = /_(x)/; r.exec(s) // ["_x", "x"] 複製程式碼
exec
方法的返回陣列還包含以下兩個屬性:
input index
如果正則表示式加上 g
修飾符,則可以使用多次 exec
方法,下一次搜尋的位置從上一次匹配成功結束的位置開始。