前言

本章介紹正則的擴展。有些不常用的知識了解即可。
本章原文鏈接:正則的擴展

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碼的模式進行匹配。處理大于/uFFFFUnicode 字符

注意

一旦加上u修飾符號,就會修改下面這些正則表達式的行為。

  1. 點字符

對于碼點大于0xFFFFUnicode 字符,點字符不能識別,必須加上u修飾符。

  1. **Unicode** 字符表示法

新增了使用大括號表示 Unicode 字符,這種表示法在正則表達式中必須加上u修飾符,才能識別當中的大括號,否則會被解讀為量詞。

  1. 量詞

使用u修飾符后,所有量詞都會正確識別碼點大于0xFFFFUnicode 字符。

  1. 預定義模式

u修飾符也影響到預定義模式,能否正確識別碼點大于0xFFFF的 Unicode 字符。

  1. i 修飾符

有些 Unicode 字符的編碼不同,但是字型很相近,比如,/u004B/u212A都是大寫的K

  1. 轉義

沒有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]*/