簡體   English   中英

Java 正則表達式交替運算符“|” 行為似乎壞了

[英]Java regex alternation operator "|" behavior seems broken

嘗試為羅馬數字編寫正則表達式匹配器。 在 sed 中(我認為它被認為是正則表達式的“標准”?),如果您有多個由交替運算符分隔的選項,它將匹配最長的選項。 即, "I|II|III|IV"將匹配“IV”的“IV”和“III”的“III”

在 Java 中,相同的模式匹配“I”代表“IV”和“I”代表“III”。 結果證明 Java 在從左到右交替匹配之間進行選擇; 也就是說,因為“I”出現在正則表達式中的“III”之前,所以它匹配。 如果我將正則表達式更改為"IV|III|II|I" ,則行為會得到糾正,但這顯然不是一般的解決方案。

有沒有辦法讓 Java 從交替組中選擇最長的匹配項,而不是選擇“第一個”?

為清楚起見,代碼示例:

public static void main(String[] args)
{
    Pattern p = Pattern.compile("six|sixty");
    Matcher m = p.matcher("The year was nineteen sixty five.");
    if (m.find())
    {
        System.out.println(m.group());
    }
    else
    {
        System.out.println("wtf?");
    }
}

這輸出"six"

不,它的行為是正確的。 Java 使用 NFA 或正則表達式導向的風格,如 Perl、.NET、JavaScript 等,sed、grep 或 awk 不同。 替代方案預計會在其中一個替代方案匹配后立即退出,而不是堅持最長的匹配。

您可以通過在交替之后添加一個條件來強制它繼續,直到整個令牌都被消耗掉才能滿足。 這種情況可能取決於上下文; 最簡單的選擇是錨點 ( $ ) 或單詞邊界 ( \\b )。

"\\b(I|II|III|IV)\\b"

編輯:我應該提到的是,雖然 grep、sed、awk 和其他傳統上使用文本導向(或 DFA)引擎,但您也可以找到其中一些使用 NFA 引擎的版本,甚至是兩者的混合。

我認為一個有效的模式是這樣的

IV|I{1,3}

請參閱http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html 上的“貪婪量詞”部分

編輯:為了回應您的評論,我認為一般的問題是您在不正確的情況下繼續使用交替。 在您的新示例中,您試圖匹配“六”或“六十”; 使用的正確模式是six(ty)? ,不是six|sixty 通常,如果您有兩個交替組的成員,其中一個是另一個的前綴,您應該重寫正則表達式以消除它。 否則,你真的不能抱怨引擎做錯了,因為交替的語義並沒有說明最長的匹配。

編輯 2:你的問題的字面答案是否定的,它不能被強迫(我的評論是你不應該需要這種行為)。

編輯 3:更多地考慮這個主題,我想到一個字符串是另一個字符串前綴的交替模式由於另一個原因是不可取的; 也就是說,除非底層自動機被構建為考慮前綴,否則它會更慢(並且鑒於 Java 選擇模式中的第一個匹配項,我猜想情況並非如此)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM