有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

用于实现toFindResult()的正则表达式Java Matcher类

根据this question,在findmatches()之间有很大的区别,但两者都以某种形式提供结果

作为一种实用程序,toMatchResult函数返回matches()操作的当前结果。我希望我在(1)下的假设是正确的。(正则表达式为here

        String line = "aabaaabaaabaaaaaab";
        String regex = "(a*b)a{3}";
        Matcher matcher = Pattern.compile(regex).matcher(line);
        matcher.find();
//        matcher.matches();(1) --> returns false because the regex doesn't match the whole string
        String expectingAab = matcher.group(1);
        System.out.println("actually: " + expectingAab);

不幸的是,以下情况不起作用(例外:未找到匹配项):

        String line = "aabaaabaaabaaaaaab";
        String regex = "(a*b)a{3}";
        String expectingAab = Pattern.compile(regex).matcher(line).toMatchResult().group(1);
        System.out.println("actually: " + expectingAab);

为什么呢?我的第一个假设是它不起作用,因为正则表达式应该匹配整个字符串;但是同样的异常也会与字符串值aabaaa一起抛出

当然,matcher需要用find()设置为正确的状态,但是如果我想使用一个oneliner呢?我实际上为此实现了一个实用程序CALS:


protected static class FindResult{
    private final Matcher innerMatcher;
    public FindResult(Matcher matcher){
        innerMatcher = matcher;
        innerMatcher.find();
    }
    public Matcher toFindResult(){
        return  innerMatcher;
    }
}

public static void main(String[] args){
    String line = "aabaaabaaabaaaaaab";
    String regex = "(a*b)a{3}";
    String expectingAab = new FindResult(Pattern.compile(regex).matcher(line)).toFindResult().group(1);
    System.out.println("actually: " + expectingAab);
}

我很清楚,这不是创建oneliner的最佳解决方案,特别是因为它会给垃圾收集器带来沉重的负载

有没有更简单、更好的解决方案

值得注意的是,我正在寻找一个解决方案java8。在Java9之上,匹配逻辑的工作方式不同


共 (2) 个答案

  1. # 1 楼答案

    toMatchResult()方法返回上一个匹配操作的状态,无论它是find()lookingAt()还是matches()

    你的线路

    String expectingAab = Pattern.compile(regex).matcher(line).toMatchResult().group(1);
    

    不调用这些方法中的任何一个,因此,将永远不会有以前的匹配项,并始终生成IllegalStateException: No match found

    如果希望使用一行程序提取第一个匹配的第一组,可以使用

    String expectingAab = line.replaceFirst(".*?(a*b)a{3}.*", "$1");
    

    模式需要在实际匹配模式之前.*?和之后.*使用剩余的字符串,并且只保留第一个组作为其内容。需要注意的是,如果不存在匹配项,它将计算为原始字符串

    因此,如果您想要matches而不是find语义,可以使用

    String expectingNoMatch = line.replaceFirst("^(a*b)a{3}$", "$1");
    

    它将与示例输入计算为原始字符串,因为它不匹配

    如果希望实用程序方法不创建FindResult实例,只需使用直接的static方法即可

    然而,这是一个典型的过早优化案例。Pattern.compile调用创建一个Pattern对象,加上一组表示模式元素的内部节点对象,matcher调用创建一个Matcher实例加上数组来保存组,toMatchResult调用创建另一个对象实例,当然,group(1)调用不可避免地会创建一个表示结果的新字符串实例

    创建FindResult实例是此行最便宜的。如果您关心性能,那么如果您多次使用该模式,您将保留Pattern.compile的结果,因为这是最昂贵的操作,Pattern实例是不可变和可共享的,正如其文档中明确说明的那样

    当然,string方法replaceFirstreplaceAll并没有什么神奇的作用,但在幕后执行相同的步骤

  2. # 2 楼答案

    该方法不需要实例字段即可工作。它可以只是一个静态辅助对象:

    class MatcherUtils {
      public static MatchResult findResult(Matcher matcher) {
        matcher.find();
        return matcher.toMatchResult();
      }
    }
    

    用法:

    MatchResult result = MatcherUtils.findResult(Pattern.compile("...").matcher("..."));
    

    请注意,当find找不到任何东西时,您可能希望处理这种情况(感谢使用一行代码,Holger!):

    class MatcherUtils {
      public static Optional<MatchResult> findResult(Matcher matcher) {
        return Optional.of(matcher)
                 .filter(Matcher::find)
                 .map(Matcher::toMatchResult);
        /*
        if (matcher.find()) {
          return Optional.of(matcher.toMatchResult());
        } else {
          return Optional.empty();
        }
        */
      }
    }