您好,登錄后才能下訂單哦!
前言
以往我們只是習慣于通過數組下標來訪問正則匹配到的分組,但分組達到4、5個時,標識起來就會非常麻煩。V8早已實現了正則命名分組提案,只是我們很少使用,本文將介紹JS的正則命名分組。
以往的做法
假設要使用正則匹配一個日期的年月日,以往我們會這樣做:
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/; const matchObj = RE_DATE.exec('1999-12-31'); const year = matchObj[1]; // 1999 const month = matchObj[2]; // 12 const day = matchObj[3]; // 31
這里有幾個缺點:
所有這些問題,都可以通過正則命名分組來解決。
現在的玩法
現在你只需要給分組里面一個命名標識即可:
(?<year>\d{4})
這里,我們用變量year標記了上一個捕獲組#1。 該名稱必須是合法的JavaScript標識符。 匹配后,您可以通過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; // 1999 const month = matchObj.groups.month; // 12 const day = matchObj.groups.day; // 31
如果正則里面有了命名分組,那么匹配結果會多了一個groups 的屬性,這個屬性中包含了一切命名分組的捕獲結果。配合上解構大法使用又是一股清流:
const {groups: {day, year}} = RE_DATE.exec('1999-12-31'); console.log(year); // 1999 console.log(day); // 31
當然,即使你使用了命名分組,那么返回的結果還可以通過以往的數組下標方式訪問:
const year2 = matchObj[1]; // 1999 const month3 = matchObj[2]; // 12 const day2 = matchObj[3]; // 31
命名分組具有以下優點:
反向引用
反向引用命名分組\k<name>
看下面這個匹配重復單詞的例子:
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/; RE_TWICE.test('abc!abc'); // true RE_TWICE.test('abc!ab'); // false
同時也可以使用以往的反向引用方式:
const RE_TWICE = /^(?<word>[a-z]+)!\1$/; RE_TWICE.test('abc!abc'); // true RE_TWICE.test('abc!ab'); // false
replace( )
字符串方法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直取最后一個參數,再接上一個解構大法,結果又是一股清流。
命名分組沒有匹配結果?
如果可選的命名組不被匹配,則其屬性值被設置為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
異常情況
分組名不能有重復項:
/(?<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
總結
以上所述是小編給大家介紹的JavaScript 正則命名分組,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。