有時我們只需要找出符合某種模式的配對,而這些配對後面或前面接著另一種模式。
這方面有特殊的語法,稱為「前瞻」和「後瞻」,合稱為「環顧」。
首先,讓我們從 1 turkey costs 30€
這樣的字串中找出價格。也就是:一個數字,後面接著 €
符號。
前瞻
語法為:X(?=Y)
,意為「尋找 X
,但僅當後接 Y
時才匹配」。X
和 Y
可以是任何模式。
對於後接 €
的整數,正規表示式將為 \d+(?=€)
let str = "1 turkey costs 30€";
alert( str.match(/\d+(?=€)/) ); // 30, the number 1 is ignored, as it's not followed by €
請注意:前瞻僅為測試,括號 (?=...)
中的內容不包含在結果 30
中。
當我們尋找 X(?=Y)
時,正規表示式引擎會找到 X
,然後檢查其後方是否緊接著 Y
。如果不是,則會略過潛在的匹配,並繼續搜尋。
可以進行更複雜的測試,例如 X(?=Y)(?=Z)
表示
- 尋找
X
。 - 檢查
Y
是否緊接在X
之後(如果不是,則略過)。 - 檢查
Z
是否也緊接在X
之後(如果不是,則略過)。 - 如果兩個測試都通過,則
X
為匹配,否則繼續搜尋。
換句話說,此類模式表示我們同時尋找後接 Y
和 Z
的 X
。
這僅在模式 Y
和 Z
互不排斥時才有可能。
例如,\d+(?=\s)(?=.*30)
尋找後接空格 (?=\s)
,且其後方某處有 30
的 \d+
(?=.*30)
let str = "1 turkey costs 30€";
alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1
在我們的字串中,完全匹配數字 1
。
負前瞻
假設我們想要同一個字串中的數量,而不是價格。這是一個數字 \d+
,後不接 €
。
為此,可以套用負前瞻。
語法為:X(?!Y)
,意為「搜尋 X
,但僅當後不接 Y
時」。
let str = "2 turkeys cost 60€";
alert( str.match(/\d+\b(?!€)/g) ); // 2 (the price is not matched)
後瞻
請注意:非 V8 瀏覽器(例如 Safari、Internet Explorer)不支援後瞻。
前瞻允許為「後續內容」新增條件。
回顧式類似,但它往後看。也就是說,它允許在前面有東西的情況下才比對樣式。
語法為
- 正向回顧式:
(?<=Y)X
,比對X
,但前提是前面有Y
。 - 負向回顧式:
(?<!Y)X
,比對X
,但前提是前面沒有Y
。
例如,我們將價格改為美金。美元符號通常在數字前面,因此要尋找 $30
,我們將使用 (?<=\$)\d+
,也就是一個前面有 $
的金額
let str = "1 turkey costs $30";
// the dollar sign is escaped \$
alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number)
而且,如果我們需要數量,也就是一個數字,且前面沒有 $
,那麼我們可以使用負向回顧式 (?<!\$)\d+
let str = "2 turkeys cost $60";
alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (the price is not matched)
擷取群組
一般來說,環顧括號內的內容不會成為結果的一部分。
例如,在樣式 \d+(?=€)
中,€
符號不會被擷取為比對的一部分。這是很自然的:我們尋找數字 \d+
,而 (?=€)
只是測試它後面應該接 €
。
但在某些情況下,我們可能也想擷取環顧式,或其一部分。這是可能的。只要將該部分包在額外的括號中即可。
在下面的範例中,貨幣符號 (€|kr)
與金額一起被擷取
let str = "1 turkey costs 30€";
let regexp = /\d+(?=(€|kr))/; // extra parentheses around €|kr
alert( str.match(regexp) ); // 30, €
以下是回顧式的相同範例
let str = "1 turkey costs $30";
let regexp = /(?<=(\$|£))\d+/;
alert( str.match(regexp) ); // 30, $
摘要
當我們想比對依賴於前後文的情況時,前瞻式和回顧式(通常稱為「環顧式」)很有用。
對於簡單的正規表示式,我們可以手動執行類似的操作。也就是說:比對任何內容,在任何上下文中,然後在迴圈中依據上下文進行篩選。
請記住,str.match
(沒有標記 g
)和 str.matchAll
(總是)會將比對結果傳回為具有 index
屬性的陣列,因此我們知道它在文字中的確切位置,並可以檢查上下文。
但一般來說,環顧式比較方便。
環顧式類型
樣式 | 類型 | 比對 |
---|---|---|
X(?=Y) |
正向前瞻式 | X 如果後面接 Y |
X(?!Y) |
負前瞻 | X 如果後面沒有接 Y |
(?<=Y)X |
正向後方參照 | X 如果在 Y 之後 |
(?<!Y)X |
負向後方參照 | X 如果不在 Y 之後 |
留言
<code>
標籤,要插入多行,請用<pre>
標籤包起來,要插入超過 10 行,請使用沙盒 (plnkr、jsbin、codepen…)