RegExp 的 Symbol 協定
July 11, 2022在〈JavaScript 字串與規則表示式〉中看過,String
上有 split
、search
、replace
與 match
方法。
Symbol 協定
在 ES6 之後,RegExp
也定義有這些方法了,不過,必須以〈符號〉來取得:
> RegExp.prototype[Symbol.split]
[Function: [Symbol.split]]
> RegExp.prototype[Symbol.search]
[Function: [Symbol.search]]
> RegExp.prototype[Symbol.replace]
[Function: [Symbol.replace]]
> RegExp.prototype[Symbol.match]
[Function: [Symbol.match]]
這表示,對於底下的這類呼叫字串方法的例子:
> 'Justin1Monica2Irene'.split(/\d/)
[ 'Justin', 'Monica', 'Irene' ]
也可以使用底下的方式:
> /\d/[Symbol.split]('Justin1Monica2Irene')
[ 'Justin', 'Monica', 'Irene' ]
實際上,ES6 在實作上,將 String
的 split
、search
、replace
與 match
方法,全都委託給傳入的 RegExp
實例上對應的方法,這麼做的原因,說法之一是這麼一來,與規則表示式相關的方法,都可以集中在 RegExp
上了,必要時你也可以繼承 RegExp
來重新定義相關的方法,例如在 MDN 的〈RegExp〉文件中,相關的方法說明中就有一些範例。
由於 JavaScript 是動態定型語言,這表示在執行 String
的 split
、search
、replace
與 match
方法時,並不一定要傳入 RegExp
實例,只要是具有 Symbol.split
、Symbol.search
、Symbol.replace
、Symbol.match
協定的物件就可以了。
安插規則
於是就有了機會,將一些外部的規則表示式程式庫,安插至 String
的規則表示式相關操作中,例如,ECMAScript 2018(ES9)之後才支援命名群組,然而,在安裝了 XRegExp 之後,可以如下支援命名群組:
const XRegExp = require('xregexp');
class Xre {
constructor(re) {
this.xRegExp = XRegExp(re);
}
[Symbol.replace](str, newSubStr) {
return XRegExp.replace(str, this.xRegExp, newSubStr);
}
}
const emailRe = new Xre('(?<user>^[a-zA-Z]+\\d*)@(?<preCom>[a-z]+?.)com');
const replaced = 'caterpillar@openhome.com'.replace(
emailRe, '${user}@${preCom}cc'
);
console.log(replaced); // 顯示 caterpillar@openhome.cc
這麼一來,JavaScript 的相關引擎實作支援命名群組之後,要將 Xre
相關的部份換成標準實作,修改幅度就會比較低一些…XD