5

我有以下兩種不同語言的正則表達式,它們產生相同的奇怪結果(javaScript和Flash)。我想知道的不是如何解決這個問題,而是爲什麼這種行爲正在發生?正則表達式只捕獲匹配中最後一個捕獲組的實例

正則表達式:

\[(\\{2}|\\\]|[^\]])*\] 

這裏的目標是匹配一個括號字符串,並確保我不會在逃脫支架停止。

如果我有文本輸入[abcdefg]它正確匹配,但作爲捕獲組的一部分返回的唯一東西是g,其中我期望abcdefg。如果我將表達式更改爲 \[((?:\\{2}|\\\]|[^\]])*)\],那麼我得到我想要的結果。

那麼爲什麼會發生這種情況呢?這會在其他語言中保持一致嗎?

說明:將表達式簡化爲\[([^\]])*\]會產生相同的問題。

回答

7

不管問題的,ActionScript和JavaScript應該總是產生相同的結果,因爲它們都實現的ECMAScript(或超集物,但對於正則表達式,他們不應該不同意)。

但是,這將會發生在任何語言(或更確切地說,任何正則表達式)。原因是你正在重複捕獲組。讓我們舉一個簡單的例子:匹配(.)*abc。所以我們重複的是(.)。第一次嘗試時,引擎進入組,匹配a.,離開組並捕獲a。量詞現在纔開始,它重複了整個事情。所以我們再次進入該組,並匹配並捕獲b。此捕獲覆蓋前一個,因此\1現在包含b。第三次重複也一樣:捕獲將被c覆蓋。

我不知道一個正則表達式的行爲不同,唯一允許您訪問所有先前捕獲(而不是覆蓋它們)的是.NET。

解決方案是一個ps.s.w.g.建議。爲重複捕獲所需的分組進行分組(這將提高性能,因爲您不需要捕獲和覆蓋所有內容)並將整個事件包裝到一個新組中。你的表情雖然有一點小缺陷:你需要在反向字符類中包含反斜槓。否則,回溯可能會給你一個匹配[abc\]。因此,這裏是一個表達式,將工作像您期望:

\[((?:\\{2}|\\\]|[^\]\\])*)\] 

Working demo.(不幸的是,它不顯示捕獲,但它表明,它給出正確的匹配在所有情況下)

請注意,您的表達式不允許其他轉義序列。特別是一個\,其次是除]之外的任何內容都會導致您的模式失敗。如果這不是你想要的東西,你可以用:

\[([^\]\\]*(?:\\.[^\]\\]*)*)\] 

Working demo.

\[((?:\\.|[^\]\\])*)\] 

Working demo.

性能可以進一步與"unrolling-the-loop"技術改進

2

嘗試包括*量詞捕獲組內,像這樣:

\[((?:\\{2}|\\\]|[^\]])*)\] 
相關問題