JavaScript正規表示式迷你書-筆記

Ryan發表於2018-10-21

貪婪模式:

在使用修飾匹配次數的特殊符號時,有幾種表示方法可以使同一個表示式能夠匹配不同的次數,比如:”{m,n}”, “{m,}”, “?”, “*”, “+”,具體匹配的次數隨被匹配的字串而定。這種重複匹配不定次數的表示式在匹配過程中,總是儘可能多的匹配

非貪婪模式:

在修飾匹配次數的特殊符號後再加上一個 “?” 號,則可以使匹配次數不定的表示式儘可能少的匹配,使可匹配可不匹配的表示式,儘可能的 “不匹配”。這種匹配原則叫作 “非貪婪” 模式,也叫作 “勉強” 模式。如果少匹配就會導致整個表示式匹配失敗的時候,與貪婪模式類似,非貪婪模式會最小限度的再匹配一些,以使整個表示式匹配成功。

var regex = /d{2,5}/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// => ["123", "1234", "12345", "12345"]

其中正則 /d{2,5}/,表示數字連續出現 2 到 5 次。會匹配 2 位、3 位、4 位、5 位連續數字。 但是其是貪婪的,它會盡可能多的匹配。你能給我 6 個,我就要 5 個。你能給我 3 個,我就要 3 個。 反正只要在能力範圍內,越多越好。

橫向模糊匹配

橫向模糊指的是,一個正則可匹配的字串的長度不是固定的,可以是多種情況的。 其實現的方式是使用量詞。譬如 {m,n},表示連續出現最少 m 次,最多 n 次。 比如正則 /ab{2,5}c/ 表示匹配這樣一個字串:第一個字元是 “a”,接下來是 2 到 5 個字元 “b”,最後是字元 “c”。


var regex = /ab{2,5}c/g;
var string = "abc abbc abbbc abbbbc abbbbbc abbbbbbc";
console.log( string.match(regex) );
// => ["abbc", "abbbc", "abbbbc", "abbbbbc"]

縱向模糊匹配

縱向模糊指的是,一個正則匹配的字串,具體到某一位字元時,它可以不是某個確定的字元,可以有多種 可能。 其實現的方式是使用字元組。
譬如 [abc],表示該字元是可以字元 “a”、”b”、”c” 中的任何一個。 比如 /a[123]b/ 可以匹配如下三種字串: “a1b”、”a2b”、”a3b”。


var regex = /d{2,5}?/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) );
// => ["12", "12", "34", "12", "34", "12", "34", "56"]
其中 /d{2,5}?/ 表示,雖然 2 到 5 次都行,當 2 個就夠的時候,就不再往

多選分支

一個模式可以實現橫向和縱向模糊匹配。而多選分支可以支援多個子模式任選其一。 具體形式如下:(p1|p2|p3),其中 p1、p2 和 p3 是子模式,用 |(管道符)分隔,表示其中任何之一。 例如要匹配字串 “good” 和 “nice” 可以使用 /good|nice/。


var regex = /good|nice/g;
var string = "good idea, nice try.";
console.log( string.match(regex) );
// => ["good", "nice"]

但有個事實我們應該注意,比如我用 /good|goodbye/,去匹配 “goodbye” 字串時,結果是 “good”

var regex = /good|goodbye/g;
var string = "goodbye";
console.log( string.match(regex) );
// => ["good"]

而把正則改成 /goodbye|good/,結果是:

var regex = /goodbye|good/g;
var string = "goodbye";
console.log( string.match(regex) );
// => ["goodbye"]

也就是說,分支結構也是惰性的,即當前面的匹配上了,後面的就不再嘗試了。

反向引用

比如要寫一個正則支援匹配如下三種格式
2016-06-12
2016/06/12
2016.06.12

var regex = /d{4}(-|/|.)d{2}(-|/|.)d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // true

其中 / 和 . 需要轉義。雖然匹配了要求的情況,但也匹配 “2016-06/12” 這樣的資料。

假設我們想要求分割符前後一致怎麼辦?此時需要使用反向引用:

var regex = /d{4}(-|/|.)d{2}1d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false

注意裡面的 1,表示的引用之前的那個分組 (-|/|.)。不管它匹配到什麼(比如 -),1 都匹配那個同 樣的具體某個字元。

我們知道了 1 的含義後,那麼 2 和 3 的概念也就理解了,即分別指代第二個和第三個分組。

使用例子

字串 trim 方法模擬

function trim(str) {
  return str.replace(/^s+|s+$/g, ``);
}

表示一個 16 進位制字元,可以用字元組 [0-9a-fA-F]。 其中字元可以出現 3 或 6 次,需要是用量詞和分支結構。 使用分支結構時,需要注意順序。 正則如下


var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
var string = "#ffbbad #Fc01DF #FFF #ffE";
console.log( string.match(regex) );
// => ["#ffbbad", "#Fc01DF", "#FFF", "#ffE"]

相關文章