Java正则表达式,奇怪的错误

时间:2013-01-30 06:03:26

标签: java regex

如果运行以下代码,我将获得false,但如果我从Pattern.CASE_INSENSITIVE删除Pattern.compile,则结果为真

public static void main(String[] args) {
    Pattern p = Pattern.compile(".*(?<!S)\\.a\\s*\\(\\s*\\)\\s*$", Pattern.CASE_INSENSITIVE);
    String s = "attributes.a()";
    Matcher m = p.matcher(s);
    System.out.println(m.matches());
}

知道发生了什么事吗?

1 个答案:

答案 0 :(得分:8)

为什么这很奇怪?它正在按预期工作,可能是由于您作为2 nd 参数传递的标志。

让我们来看看你的模式: -

".*(?<!S)\\.a\\s*\\(\\s*\\)\\s*$"

您的模式将匹配S之前没有.a的字符串。从您的模式的下面部分可以清楚地看出这一点。

(?<!S)\\.a  // Match if `.a` is not preceded by `S`.

现在,当您使用Pattern.CASE_INSENSITIVE时,此条件会在s之前检查S.a,如果其中任何一个存在,则不匹配它。所以你的模式真的变成了: -

(?<![sS])\\.a  // Match if `.a` is not preceded by `S` or `s`.

现在,在你的字符串中: -

"attributes.a()"

s之前你有.a个小{}}。因此,代码中的模式将为此字符串返回true,并启用不区分大小写标记。


仅供参考,您也可以使用(?i)标志而不是传递Pattern.CASE_INSENSITIVE的第二个参数来查看相同的效果。所以下面的模式与你的相同: -

Pattern p = Pattern.compile("(?i).*(?<!S)\\.a\\s*\\(\\s*\\)\\s*$");

使用(?i)的优势在于,您可以使用它只制作模式CASE_INSENSITIVE的一部分。例如,如果您希望仅检查(?<!S),但以下字符串可以是.a.A,那么您可以在(?i)之前使用.a }: -

Pattern p = Pattern.compile(".*(?<!S)(?i)\\.a\\s*\\(\\s*\\)\\s*$");
                                      ^^^

现在,(?i)标记后的整个模式将以CASE_INSENSITIVE方式匹配。


另外,请注意,您并不需要在评论中指出 look-behind 不区分大小写匹配。如果您的信件只应为[^S],则只需使用[aA]a即可。因为 look-behinds 不区分大小写会带来一些性能差异。因此,您只需将模式更改为: -

Pattern p = Pattern.compile(".*[^S][.][aA][ ]*[(][ ]*[)][ ]*$");

我还用character class替换了反斜杠。我更喜欢使用它,而不是双重转义元字符。但这只是一个品味问题。你可以随心所欲地使用它。