前言
本章介紹正則的擴展。有些不常用的知識了解即可。
本章原文鏈接:正則的擴展
RegExp 構造函數
從 ES6 開始,如果RegExp
構造函數第一個參數是一個正則對象,并且第二個標志存在且為標志參數,將不再拋出 TypeError
,將使用這些參數創建一個新的正則表達式。原有的正則表達式修飾符將被忽略
const flag = new RegExp(/[0-9]/ig, i).flags; // 原有修飾符衛 ig ,被 i 給替代了console.log(flag); // i
字符串有關正則表達式
ES6將之前字符串上的四個關于正則表達式的方法全部更改為RegExp
的實例方法,所以現在所有與正則表達式有關的方法,全部定義在RegExp
對象上。
String.prototype.match
調用RegExp.prototype[Symbol.match]
String.prototype.replace
調用RegExp.prototype[Symbol.replace]
String.prototype.search
調用RegExp.prototype[Symbol.search]
String.prototype.split
調用RegExp.prototype[Symbol.split]
flags 屬性
RegExp.prototype.flags
屬性 是ES6新增屬性,會返回正則表達式的修飾符。
const SAMPLEREG = /abc/ig;console.log(SAMPLEREG.flags); // gi
u 修飾符
在ES6中新增了 u
修飾符,表示使用Unicode
碼的模式進行匹配。處理大于/uFFFF
的 Unicode
字符
注意
一旦加上u
修飾符號,就會修改下面這些正則表達式的行為。
- 點字符
對于碼點大于0xFFFF
的 Unicode
字符,點字符不能識別,必須加上u
修飾符。
**Unicode**
字符表示法
新增了使用大括號表示 Unicode
字符,這種表示法在正則表達式中必須加上u
修飾符,才能識別當中的大括號,否則會被解讀為量詞。
- 量詞
使用u
修飾符后,所有量詞都會正確識別碼點大于0xFFFF
的 Unicode
字符。
- 預定義模式
u
修飾符也影響到預定義模式,能否正確識別碼點大于0xFFFF的 Unicode 字符。
i
修飾符
有些 Unicode
字符的編碼不同,但是字型很相近,比如,/u004B
與/u212A
都是大寫的K
- 轉義
沒有u
修飾符的情況下,正則中沒有定義的轉義(如逗號的轉義/,
)無效,而在u模式會報錯。
unicode 屬性
RegExp.prototype.unicode
屬性表明正則表達式帶有"u
" 標志。 unicode
是正則表達式獨立實例的只讀屬性。
const SAMPLEREG = /abc/u;console.log(SAMPLEREG.flags); // uconsole.log(SAMPLEREG.unicode); // true
Unicode 屬性類
**Unicode property escapes**
ES2018 引入了一種新的類的寫法/p{...}
和`P{...},用于解決 JavaScript 沒有強有效的方式用匹配出不同文字問題。允許正則表達式匹配符合
Unicode` 某種屬性的所有字符。
/p{Unicode屬性名=Unicode屬性值}// 對于某些屬性,可以只寫屬性名,或者只寫屬性值。/p{Unicode屬性值}/p{Unicode屬性名}// /P 為 /p 取反/P{Unicode屬性值}/P{Unicode屬性名}
注意:
這兩種類只對 Unicode
有效,所以使用的時候一定要加上u
修飾符。/P{…}
是/p{…}
的反向匹配,即匹配不滿足條件的字符。
const SAMPLEREG = //p{Script=Greek}/u;SAMPLEREG.test(π); // true
y 修飾符
y 修飾符的作用
在ES6中新增了 y
修飾符,表示執行“粘性(sticky)”搜索,匹配從目標字符串的當前位置開始。
y
修飾符與g
修飾符相似,都是全局匹配,后一次匹配從上一次匹配成功的下一個位置開始。
區別是:g
修飾符只要剩余位置中存在匹配即可;而y
修飾符必須從剩余的第一個位置開始匹配。
// y修飾符與g修飾符的區別const SAMPLE = abcdabcd;const SAMPLEREG1 = /abcd/g;const SAMPLEREG2 = /abcda/y;console.log(SAMPLEREG1.test(SAMPLE)); // trueconsole.log(SAMPLEREG2.test(SAMPLE)); // trueconsole.log(SAMPLEREG1.test(SAMPLE)); // trueconsole.log(SAMPLEREG2.test(SAMPLE)); // false
注意
實際上,y
修飾符號隱含了頭部匹配的標志^
。
const SAMPLEREGGY = /ab/gy;const SAMPLEREGY = /ab/y;let sample1 = ababcabcd.replace(SAMPLEREGGY, -); let sample2 = ababcabcd.replace(SAMPLEREGY, -);// 最后一個ab因為不是出現在下一次匹配的頭部,所以不會被替換。console.log(sample1);// 只能返回第一個匹配,必須與g修飾符聯用,才能返回所有匹配。console.log(sample2);
sticky 屬性
RegExp.prototype.sticky
表示是否設置了y
修飾符。sticky
是正則表達式對象的只讀屬性。
const SAMPLEREG = /a/gy;console.log(SAMPLEREG.sticky); // true
s 修飾符
ES2018 引入s
修飾符,使得.
可以匹配任意單個字符。包括行終止符(line terminator character)。
行終止符
所謂行終止符,就是該字符表示一行的終結。以下四個字符屬于“行終止符”。
U+000A
換行符(/n
)U+000D
回車符(/r
)U+2028
行分隔符(line separator
)U+2029
段分隔符(paragraph separator
)
const SAMPLEREG = /ab.cd/s;console.log(SAMPLEREG.test(ab/ncd) ); // true
dotAll
上面這種情況被稱為**dotAll**
模式,即點(dot)代表一切字符。正則表達式還引入了一個**dotAll**
屬性dotAll
屬性返回一個布爾值,表明是否在正則表達式中一起使用"s
"修飾符。dotAll
是一個只讀的屬性,屬于單個正則表達式實例。
const SAMPLEREG = /ab.cd/s; const sample = SAMPLEREG.test(ab/ncd); console.log(SAMPLEREG.flags); // s console.log(SAMPLEREG.dotAll); // true
后行斷言
ES2018 引入后行斷言,V8 引擎 4.9 版(Chrome 62)已經支持。
先行斷言
x
只有在y
前面才匹配,必須寫成/x(?=y)/
。
比如,只匹配百分號之前的數字,要寫成//d+(?=%)/
。先行否定斷言
,x
只有不在y
前面才匹配,必須寫成/x(?!y)/
。
比如,只匹配不在百分號之前的數字,要寫成//d+(?!%)/
。后行斷言
正好與先行斷言
相反,x
只有在y
后面才匹配,必須寫成/(?<=y)x/
。
比如,只匹配美元符號之后的數字,要寫成/(?<=/$)/d+/
。后行否定斷言
則與先行否定斷言
相反,x
只有不在y
后面才匹配,必須寫成/(?<!y)x/
。
比如,只匹配不在美元符號后面的數字,要寫成/(?<!/$)/d+/
。
后行斷言需要先匹配/(?<=y)x/
的x
,然后再回到左邊,匹配y
的部分。順序為先右后左,
// 先行斷言const sample1 = //d+(?=%)/.exec(100% of US presidents have been male);// 先行否定斷言const sample2 = //d+(?!%)/.exec(that’s all 44 of them);console.log(sample1); // 100console.log(sample2); // 44// 后行斷言const sample3 = /(?<=/$)/d+/.exec(Benjamin Franklin is on the $100 bill);// 后行否定斷言const sample4 = /(?
組匹配
正則表達式的括號表示分組匹配,括號中的模式可以用來匹配分組的內容。
ES2018 引入了具名組匹配(Named Capture Groups),允許為每一個組匹配指定一個名字,既便于閱讀代碼,又便于引用。
具名組匹配在圓括號內部,模式的頭部添加“問號 + 尖括號 + 組名”(?<year>)
,然后就可以在exec
方法返回結果的groups
屬性上引用該組名。同時,數字序號依然有效。
const sampleUsers = `姓劉名備字玄德姓關名羽字云長姓張名飛字翼德`;const SAMPLEREG = /姓(?
上面的代碼中:
?<xxx>
的作用就是為這個匹配定義一個組名,在匹配的groups
屬性中可以查看到匹配的組名,這里可以使用解構賦值直接從匹配結果上為變量賦值。
注意 : 如果要在正則表達式內部引用某個具名組匹配,可以使用
/k<組名>
的寫法
matchAll()
ES2020 增加了
String.prototype.matchAll()
方法,可以一次性取出所有匹配。不過,它返回的是一個遍歷器/迭代器(Iterator
),而不是數組。
const string = sample1sample2sample3;const regex = /sample/g;for (const match of string.matchAll(regex)) { console.log(match);}// 遍歷輸出/*[sample, index: 0, input: sample1sample2sample3, groups: undefined][sample, index: 7, input: sample1sample2sample3, groups: undefined][sample, index: 14, input: sample1sample2sample3, groups: undefined]*/