摘要:早已實現了正則命名分組提案,只是我們很少使用,本文將介紹的正則命名分組。所有這些問題,都可以通過正則命名分組來解決。該名稱必須是合法的標識符。
前言
以往我們只是習慣于通過數組下標來訪問正則匹配到的分組,但分組達到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
這里有幾個缺點:
要找到一個分組的位置,你必須要去數括號的位置,有時嵌套起來會更令人頭疼。
后面維護代碼的同學閱讀起來,還要根據下標找到正則里面對應的括號,并且要再次閱讀括號里面的正則才知道含義。
當你調整正則捕獲分組的數量、順序或嵌套時,你必要還要對下面的代碼做調整。
所有這些問題,都可以通過正則命名分組來解決。
現在的玩法現在你只需要給分組里面一個命名標識即可:
(?d{4})
這里,我們用變量year標記了上一個捕獲組#1。 該名稱必須是合法的JavaScript標識符。 匹配后,您可以通過matchObj.groups.year訪問捕獲的字符串。
讓我們通過命名分組重寫前面的代碼:
const RE_DATE = /(?d{4})-(? d{2})-(? 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 month2 = matchObj[2]; // 12 const day2 = matchObj[3]; // 31
命名分組具有以下優點:
找到分組的“ID”更容易。
匹配的代碼變得自描述性,因為分組的ID描述了捕獲的內容。
如果更改分組的順序,則不必更改匹配的代碼。
分組的名稱也使正則表達式更易于理解,因為您可以直接看到每個組的用途。
反向引用反向引用命名分組k
看下面這個匹配重復單詞的例子:
const RE_TWICE = /^(?[a-z]+)!k $/; RE_TWICE.test("abc!abc"); // true RE_TWICE.test("abc!ab"); // false
同時也可以使用以往的反向引用方式:
const RE_TWICE = /^(?replace( )[a-z]+)!1$/; RE_TWICE.test("abc!abc"); // true RE_TWICE.test("abc!ab"); // false
字符串方法replace()以兩種方式支持命名分組:
方式一const RE_DATE = /(?d{4})-(? d{2})-(? d{2})/; console.log("1999-12-31".replace(RE_DATE, "$ /$ /$ ")); // 12/31/1999
如果replace不一定是直接返回新的拼接字符串,那么可以看看下面的辦法:
方式二const RE_DATE = /(?d{4})-(? d{2})-(? 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 = /^(?異常情況a+)?$/; const matchObj = RE_OPT_A.exec(""); // We have a match: console.log(matchObj[0] === ""); // true // Group didn’t match anything: console.log(matchObj.groups.as === undefined); // true // But property as exists: console.log("as" in matchObj.groups); // true
分組名不能有重復項:
/(?a)(? b)/ // SyntaxError: Duplicate capture group name
反向引用一個不存在的分組名:
/k/u // SyntaxError: Invalid named capture referenced /k /.test("k ") // true, 非 Unicode 下為了向后兼容,k 前面的 會被丟棄
在 reaplce() 方法的替換字符串中引用一個不存在的分組:
"abc".replace(/(?最后.*)/, "$ ") // SyntaxError: Invalid replacement string "abc".replace(/(.*)/, "$ ") // "$ ",不包含命名分組時會向后兼容
Chrome60 已支持命名分組
通過babel插件處理兼容問題
babel-plugin-transform-modern-regexp
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108016.html
摘要:在中就體現成用正則表達式進行文件名匹配。字符串匹配恩,那么不包括呢顯然,這就需要用到正則的位置匹配了和都是不正確的,匹配前面不是的的位置。參考正則表達式分鐘入門教程正則表達式匹配不包含某個字符串通俗易懂還有圖 問題重現 不知道各位旁友在webpack的使用中,有沒有碰到下面的問題情景: 在使用了css Module的情況下,同時又希望用一些global的布局,其實在css Module...
摘要:非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。 導讀 你有沒有在搜索文本的時候絞盡腦汁, 試了一個又一個表達式, 還是不行. 你有沒有在表單驗證的時候, 只是做做樣子(只要不為空就好), 然后燒香拜佛, 虔誠祈禱, 千萬不要出錯. 你有沒有在使用sed 和 grep 命令的時候, 感覺莫名其妙, 明明應該支持的元字符, 卻就是匹配不到. 甚至,...
摘要:自從年推出標準第版以來,正則表達式已成為語言的一部分。最后,如果在正則表達式中使用了命名捕獲組,則將它們放在屬性中。支持與相同語法的命名組已經模仿了的正則表達式語法。下面是一個例子此正則表達式在句子中查找連續的重復單詞。 翻譯:瘋狂的技術宅原文:https://www.smashingmagazine.... 本文首發微信公眾號:jingchengyideng歡迎關注,每天都給你推...
摘要:在默認的模式下,元字符和分別匹配字符串的開頭和結尾處,模式改變了這倆元字符的定義,讓他們匹配一行的開頭和結尾。可以使用非捕獲元字符或來忽略對這部分正則表達式的保存。 一、背景 工作上遇到一個這樣的需求: 用正則表達式將一個字符串中的span標簽替換為img標簽,并將原span標簽的內容放到img標簽的src中,問題詳細描述:點我 看到這個需求,我知道應該可以用正則表達式,可是由于之前沒...
閱讀 2418·2021-11-16 11:44
閱讀 852·2021-09-10 11:16
閱讀 2228·2019-08-30 15:54
閱讀 1057·2019-08-30 15:53
閱讀 1900·2019-08-30 13:00
閱讀 620·2019-08-29 17:07
閱讀 3513·2019-08-29 16:39
閱讀 3138·2019-08-29 13:30