前言
以往我們只是習(xí)慣于通過數(shù)組下標(biāo)來訪問正則匹配到的分組,但分組達(dá)到4、5個時,標(biāo)識起來就會非常麻煩。V8早已實現(xiàn)了正則命名分組提案,只是我們很少使用,本文將介紹JS的正則命名分組。
以往的做法
假設(shè)要使用正則匹配一個日期的年月日,以往我們會這樣做:
const RE_DATE = /(/d{4})-(/d{2})-(/d{2})/;const matchObj = RE_DATE.exec('1999-12-31');const year = matchObj[1]; // 1999const month = matchObj[2]; // 12const day = matchObj[3]; // 31這里有幾個缺點(diǎn):
所有這些問題,都可以通過正則命名分組來解決。
現(xiàn)在的玩法
現(xiàn)在你只需要給分組里面一個命名標(biāo)識即可:
	(?<year>/d{4})
這里,我們用變量year標(biāo)記了上一個捕獲組#1。 該名稱必須是合法的JavaScript標(biāo)識符。 匹配后,您可以通過matchObj.groups.year訪問捕獲的字符串。
讓我們通過命名分組重寫前面的代碼:
const RE_DATE = /(?<year>/d{4})-(?<month>/d{2})-(?<day>/d{2})/;const matchObj = RE_DATE.exec('1999-12-31');const year = matchObj.groups.year; // 1999const month = matchObj.groups.month; // 12const day = matchObj.groups.day; // 31如果正則里面有了命名分組,那么匹配結(jié)果會多了一個groups 的屬性,這個屬性中包含了一切命名分組的捕獲結(jié)果。配合上解構(gòu)大法使用又是一股清流:
const {groups: {day, year}} = RE_DATE.exec('1999-12-31');console.log(year); // 1999console.log(day); // 31當(dāng)然,即使你使用了命名分組,那么返回的結(jié)果還可以通過以往的數(shù)組下標(biāo)方式訪問:
const year2 = matchObj[1]; // 1999const month2 = matchObj[2]; // 12const day2 = matchObj[3]; // 31
命名分組具有以下優(yōu)點(diǎn):
反向引用
反向引用命名分組/k<name>
看下面這個匹配重復(fù)單詞的例子:
const RE_TWICE = /^(?<word>[a-z]+)!/k<word>$/;RE_TWICE.test('abc!abc'); // trueRE_TWICE.test('abc!ab'); // false同時也可以使用以往的反向引用方式:
const RE_TWICE = /^(?<word>[a-z]+)!/1$/;RE_TWICE.test('abc!abc'); // trueRE_TWICE.test('abc!ab'); // falsereplace( )
字符串方法replace()以兩種方式支持命名分組:
方式一
const RE_DATE = /(?<year>/d{4})-(?<month>/d{2})-(?<day>/d{2})/;console.log('1999-12-31'.replace(RE_DATE, '$<month>/$<day>/$<year>')); // 12/31/1999如果replace不一定是直接返回新的拼接字符串,那么可以看看下面的辦法:
方式二
const RE_DATE = /(?<year>/d{4})-(?<month>/d{2})-(?<day>/d{2})/;console.log('1999-12-31'.replace( RE_DATE, (g, y, m, d, offset, input, {year, month, day}) =>  month+'/'+day+'/'+year)); // 12/31/1999看看這replace的callback形參密密麻麻看得心慌慌,很多都用不上,那么我們看看更簡單的寫法:
console.log('1999-12-31'.replace(RE_DATE, (...args) => {  const {year, month, day} = args.slice(-1)[0];  return month+'/'+day+'/'+year; })); // 12/31/1999這里配合上spread operator直取最后一個參數(shù),再接上一個解構(gòu)大法,結(jié)果又是一股清流。
命名分組沒有匹配結(jié)果?
如果可選的命名組不被匹配,則其屬性值被設(shè)置為undefined,但key是仍存在:
const RE_OPT_A = /^(?<as>a+)?$/;const matchObj = RE_OPT_A.exec('');// We have a match:console.log(matchObj[0] === ''); // true// Group <as> didn't match anything:console.log(matchObj.groups.as === undefined); // true// But property as exists:console.log('as' in matchObj.groups); // true異常情況
分組名不能有重復(fù)項:
/(?<foo>a)(?<foo>b)/ // SyntaxError: Duplicate capture group name
反向引用一個不存在的分組名:
//k<foo>/u // SyntaxError: Invalid named capture referenced//k<foo>/.test("k<foo>") // true, 非 Unicode 下為了向后兼容,k 前面的 / 會被丟棄在 reaplce() 方法的替換字符串中引用一個不存在的分組:
"abc".replace(/(?<foo>.*)/, "$<bar>") // SyntaxError: Invalid replacement string"abc".replace(/(.*)/, "$<bar>") // "$<bar>",不包含命名分組時會向后兼容
最后
babel-plugin-transform-modern-regexp
總結(jié)
以上所述是小編給大家介紹的JavaScript 正則命名分組,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對VeVb武林網(wǎng)網(wǎng)站的支持!
新聞熱點(diǎn)
疑難解答