沐鳴登錄網站_Javascript正則中的命名捕獲分組

假設你在一段陌生的代碼中看到這樣一個函數: 

function toLocalDate(date) {
  return date.replace(/(\d{2})-(\d{2})-(\d{4})/, "$2-$1-$3")
}

單看這個函數你能知道它是想把“日-月-年”替換成“月-日-年”,還是反過來?匿名捕獲分組沒法做到這一點,那就該命名捕獲分組上場了:

function toLocalDate(date){
  return date.replace(/(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/, "$<day>-$<month>-$<year>")
}

俗話說的好,“一個好的變量名賽過一行註釋”,命名捕獲分組很大的一個作用就是它能起到註釋的作用。

另外,命名捕獲分組還有一個好處,那就是假如你在修改一個正則時,在已有分組的左邊引入了新的分組,那麼你還得記得更新已有的反向引用的数字。比如將 (foo)\1 改成了 (bar)(foo)\1,那你得把原來的 \1 改成 \2,replace() 方法的第二個參數里的 $1 也同樣得改,用命名分組不會有這個問題。

語法

命名捕獲分組自身的語法是 (?<name>…),比普通的分組多了一個 ?<name> 字樣,其中 name 的起法就和你平時起變量名一樣即可(不過在這裏關鍵字也可用)。

反向引用一個命名分組的語法是 \k<name>,注意命名分組同樣可以通過数字索引來反向引用,比如:

/(?<foo>a)\k<foo>\1/.test("aaa") // true

在 replace() 方法的替換字符串中反向引用是用 $<name>:

"abc".replace(/(?<foo>a)/, "$<foo>-") // "a-bc",同樣 $1 仍然可用

總結一下就是,和命名分組相關的有三種語法,分別是 ?<name>、\k<name>、$<name>,相同點是都用尖括號包裹着分組名。

在 API 中的使用

在 exec() 和 match() 中的使用:

const groups = "04-25-2017".match(/(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/).groups // {month: "04", day: "25", year: "2017"}

const {day, month, year} = groups

exec() 和 match() 方法返回的匹配結果數組上多了一個 groups 屬性,裏面存放着每個命名分組的名稱以及它們匹配到的值,利用 ES6 的解構語法,可以方便的提取出想要的字段。注意這個 groups 屬性只有在當前正則里至少存在一個命名分組的前提下才會存在,比如:

/(\d{2})-(\d{2})-(\d{4})/.exec("04-25-2017").groups // undefined,因為沒有命名分組

在 replace(/…/, replacement) 中的使用:

replacement 是字符串的情況上面已經舉過例子了,這裏主要講它是函數的情況:

"04-25-2017".replace(/(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/, (...args) => {
  const groups = args.slice(-1)[0]
  const {day, month, year} = groups
  return `${day}-${month}-${year}`
}) // "25-04-2017"

也就是說,在實參列表的最末尾,多傳了一個 groups 對象。同樣,如果正則里沒有命名分組,這個參數不會存在。

異常情況

分組名不能有重複項:

/(?<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>",不包含命名分組時會向後兼容

總結

V8 目前已經完全實現了命名捕獲分組的提案 https://tc39.github.io/proposal-regexp-named-groups/。

命名分組雖然帶來了一些好處,但我個人覺得,正則越長越難讀懂,尤其增加的長度是一堆小括號和尖括號。在可讀性上,命名分組也許會起到反作用,尤其對正則苦手來說。 

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

鏈接: http://www.fly63.com/article/detial/10196