X?正则表达量词没有按预期工作(由我)

时间:2014-10-13 18:16:54

标签: java regex

输入字符串:

  • aaa---foo---ccc---ddd
  • aaa---bar---ccc---ddd
  • aaa---------ccc---ddd

正则表达式:aaa.*(foo|bar)?.*ccc.*(ddd)

此正则表达式在任何情况下都找不到第一组(foo | bar)。对于捕获组1,它始终返回null。 我的问题是为什么以及如何避免这种情况。

这是我的正则表达式的简单示例。如果我删除?量词,但输入字符串可以完全没有此组(aaa---------ccc---ddd),那么它仍然有用,我仍然需要确定它是foo还是bar还是{ {1}}。但是第1组始终是null

使用此正则表达式和测试字符串的页面:http://fiddle.re/45c766

3 个答案:

答案 0 :(得分:3)

如果要捕获中间foobar字符串,请将正则表达式更改为以下内容。

aaa(?:(?!foo|bar).)*(foo|bar)?.*?ccc.*?(ddd)

由于.*也会占用中间字符串foobar,因此您可以使用(?:(?!foo|bar).)*而不是(?:(?!foo|bar).)*。这个foo正则表达式会匹配任何字符,但不会匹配barString s = "aaa---foo---ccc---ddd\n" + "aaa---bar---ccc---ddd\n" + "aaa---------ccc---ddd"; Pattern regex = Pattern.compile("aaa(?:(?!foo|bar).)*(foo|bar)?.*?ccc.*?(ddd)"); Matcher matcher = regex.matcher(s); while(matcher.find()){ System.out.println(matcher.group(1)); } 零次或多次。

DEMO

foo
bar
null

<强>输出:

{{1}}

答案 1 :(得分:3)

这就是为什么它不起作用:当你在模式中有.*时,匹配器的算法就是尝试匹配尽可能多的字符来制作其余的模式工作。在这种情况下,如果它尝试从字符串的整个剩余部分开始.*并删除一个字符直到匹配,则会发现(对于"aaa---foo---ccc---ddd")它将有效.*匹配9个字符;那么(foo|bar)?并不匹配任何东西,这是可以的,因为它是可选的;并且下一个.*匹配0个字符,然后其余模式匹配。这就是它选择的那个。

.*更改为.*?的原因:

aaa.*?(foo|bar)?.*?ccc.*(ddd)   

不起作用的是匹配器反向做同样的事情。它以0字符匹配开始,然后确定它是否可以使模式工作。尝试此操作时,会发现它可以使.*?匹配0个字符;那么(foo|bar)?并不匹配任何东西;然后第二个.*?匹配9个字符;那么模式的其余部分匹配ccc---ddd。无论哪种方式,它都不会做你想做的事。

答案中有几个解决方案,都涉及前瞻性。这是另一个解决方案:

aaa.*(foo|bar).*ccc.*(ddd)|aaa.*ccc.*(ddd)

这基本上按顺序检查两种模式;首先检查其中是否有foo|bar的模式,如果匹配不匹配,则会搜索另一种可能性,而不是foo|bar。如果有foo|bar,我们总会找到它。

然而,所有这些解决方案都涉及相当难以阅读的正则表达式。这就是我编写它的方式:

Pattern pat1 = Pattern.compile("aaa(.*)ccc.*ddd");
Pattern pat2 = Pattern.compile("foo|bar");

Matcher m1 = pat1.matcher(source);
String foobar;
if (m1.matches()) {
    Matcher m2 = pat2.matcher(m1.group(1));
    if (m2.find()) {
        foobar = m2.group(0);
    } else {
        foobar = null;
    }
}

通常,尝试使用一个whiz-bang正则表达式来解决问题会导致代码不太可读(并且可能效率较低),而不仅仅是将问题分解为部分。

答案 2 :(得分:-2)

尝试:

.{3}\-{3}(.{3})\-{3}.{3}\-{3}(.{3})