为什么我的正则表达式适用于RegexPlanet和regex101,但不适用于我的代码?

时间:2015-09-07 07:16:56

标签: java regex

给定字符串#100=SAMPLE('Test','Test',我要提取100Test。我为此目的创建了正则表达式^#(\d+)=SAMPLE\('([\w-]+)'.*

我在RegexPlanetregex101上测试了正则表达式。这两个工具都给了我预期的结果,但当我尝试在我的代码中使用它时,我没有得到匹配。我使用以下代码片段来测试正则表达式:

final String line = "#100=SAMPLE('Test','Test',";
final Pattern pattern = Pattern.compile("^#(\\d+)=SAMPLE\\('([\\w-]+)'.*");
final Matcher matcher = pattern.matcher(line);

System.out.println(matcher.matches());
System.out.println(matcher.find());
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));

输出

true
false
Exception in thread "main" java.lang.IllegalStateException: No match found
    at java.util.regex.Matcher.group(Matcher.java:536)
    at java.util.regex.Matcher.group(Matcher.java:496)
    at Test.main(Test.java:15)

我使用Java 8编译和运行程序。为什么正则表达式适用于在线工具但不适用于我的程序?

3 个答案:

答案 0 :(得分:3)

Matcher对象允许您多次查询,以便您可以找到表达式,获取组,再次查找表达式,获取组等等。

这意味着它会在每次通话后保持状态 - 包括成功匹配产生的组以及继续搜索的位置。

当您连续运行两个匹配/查找方法时,您拥有的是:

  1. matches() - 在字符串开头匹配,设置组。
  2. find() - 尝试在先前匹配/找到的事件之后找到下次出现的模式,设置组。
  3. 但是,当然,在您的情况下,文本不包含两个模式的出现,只有一个。因此虽然matches()成功并设置了正确的组,但find()无法找到另一个匹配,并且这些组无效(在匹配/查找失败后无法访问这些组)。

    这就是您收到错误消息的原因。

    现在,如果你只是在玩这个,看看matchesfind之间的区别,那么在程序中同时使用它们并没有错。但是你需要在它们之间使用reset(),这将导致find()不要尝试从matches()停止的地方继续(如果matches()成功,它将永远失败)。相反,它将从头开始扫描,就好像你有一个新的Matcher。它会成功并为你提供团体。

    但正如其他答案所暗示的那样,如果您不只是想比较matchesfind的结果,而只是想匹配您的模式并获得结果,那么您应该只选择一个

    • matches()会尝试匹配整个字符串。出于这个原因,如果成功,在它之后运行find()永远不会成功 - 因为它开始在字符串的末尾搜索。如果您使用matches(),则在模式的开头和结尾处不需要^$等锚点。
    • find()会尝试匹配字符串中的任意位置。它将从左侧开始扫描,但不要求实际匹配从那里开始。也可以多次使用它。
    • lookingAt()将尝试在字符串的开头匹配,但不一定匹配完整的字符串。这就像在你的模式的开头有一个^锚点。

    因此,您选择哪一个适合您,并使用它,然后您可以使用这些组。在尝试使用组之前,始终测试匹配是否成功!

答案 1 :(得分:1)

正如@RealSkeptic所提到的,您应该删除代码中对matcher.find()的调用,这是在您有机会找到所有组并将其输出到控制台之前推进匹配器。其余代码保持不变:

final String line = "#100=SAMPLE('Test','Test',";
final Pattern pattern = Pattern.compile("^#(\\d+)=SAMPLE\\('([\\w-]+)'.*");
final Matcher matcher = pattern.matcher(line);

System.out.println(matcher.matches());
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));

<强>输出:

true
100
Test

答案 2 :(得分:0)

看看这个,如果我理解正确,这就是你想要实现的目标:

public class test {
    public static void main(String[] args) {
        final String line = "#100=SAMPLE('Test','Test',";
        final Pattern pattern = Pattern.compile("^#(\\d+)=SAMPLE\\('([\\w-]+)'.*");
        final Matcher matcher = pattern.matcher(line);

        if (matcher.find()) {
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));
        }
    }
}