正则表达式Matcher上的奇怪行为

时间:2012-11-27 21:37:51

标签: java regex

我的正则表达式应该过滤掉长度为8-10的大写单词,其中可能出现0-2个数字。它一直在我的所有测试中工作,但由于某种原因它被卡在下面的字符串上。并且n.group(0)仅包含空字符串而不是匹配的“单词”。

static final Pattern PATTERN = 
    Pattern.compile("\\b(?=[A-Z\\d]{9,10}\\b)(?:[A-Z]*\\d){0,2}[A-Z]*\\b");

Matcher n = LONG_PASSWORD.matcher("foo ID:636152727 bar");

while (n.find()) {
    String s = n.group(0);                  
    resultArrayList.add(s);
}

为什么我的模式与ID:636152727匹配?

我想过滤的一些例子(工作正常):

  • AAAAAAAAAA
  • 1AAAAAAAAA
  • 1AAAAAAAA1

等...

2 个答案:

答案 0 :(得分:2)

我没有比Ωmega的答案提供更好的解决方案,但我想我可以解释发生了什么。它归结为第一个\b和最后一个\b匹配相同的位置:在冒号后面。

这是前瞻可以匹配的第一个地方,因为它后跟九个数字和一个单词边界。然后正则表达式的下一部分尝试匹配两个数字(散布有任意数量的大写字母)后跟一个单词边界,并失败。所以它试图只匹配一个数字(同上),并再次失败。然后它尝试匹配数字(散布着字母),并且它成功,而不提前匹配位置。该位置仍然是一个单词边界,因此最终的\b也会成功。

单词边界只是另一个零宽度断言,比如前瞻和后瞻。没有理由不能在同一地点使用两个或更多个;你是故意用第一个单词边界和前瞻来做的。如果将量词应用于断言(如\b+),某些正则表达式会将其视为错误,但我认为它们中的任何一个都不会遇到此问题。这是一个罕见的例子,其中单独的单词开头和词尾结束断言,如GNU的\<\>或TCL的\y\Y,有所作为。

答案 1 :(得分:1)

<击> 您需要使用锚点^$»

Pattern.compile("^(?=[A-Z\\d]{9,10}$)(?:[A-Z]*\\d){0,2}[A-Z]*$");

<击>

使用此模式:

"(?:^|(?<=\\s))(?=[A-Z\\d]{9,10}(?:\\s|$))(?:[A-Z]*\\d){0,2}[A-Z]*(?=\\s|$)"