Java正则表达式交替运算符“ |”行为似乎破了

试图为罗马数字编写正则表达式匹配器。在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或regex指导的风格,如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选择模式中的第一个匹配,我猜这不是这种情况)。     

要回复问题请先登录注册