实现toFindResult()的JavaMatcher类
根据这个问题,find和之间有很大的区别matches(),仍然以某种形式提供结果。
作为一种实用程序,该toMatchResult函数返回matches()操作的当前结果。我希望我的假设(1)是有效的。(正则表达式在这里)
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......
当然,匹配器需要使用 设置为正确的状态find(),但是如果我想使用 oneliner 呢?我实际上为此实现了一个实用程序类:
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. 匹配逻辑在 java 9 之上的工作方式有所不同。
回答
该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实例是不可变和可共享的,如其文档中明确所述。
当然,字符串方法replaceFirst并replaceAll没有什么神奇之处,只是在幕后执行相同的步骤。