Java 匹配器 class 实现 toFindResult()
Java Matcher class to implement toFindResult()
根据 this question,find
和 matches()
之间存在很大差异,但两者都以某种形式提供结果。
作为一种实用程序,toMatchResult
函数 returns 具有 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
也会抛出相同的异常...
当然需要使用 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.
上面的匹配逻辑不同
该方法不需要实例字段即可工作。它可以只是一个静态助手:
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();
}
*/
}
}
toMatchResult()
方法returns之前匹配操作的状态,无论是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}.*", "");
该模式在实际匹配模式之前需要 .*?
并且在实际匹配模式之后需要 .*
,以消耗剩余的字符串并仅保留第一组作为其内容。需要注意的是,如果不存在匹配项,它将评估为原始字符串。
所以如果你想要 matches
而不是 find
语义,你可以使用
String expectingNoMatch = line.replaceFirst("^(a*b)a{3}$", "");
这将使用示例输入评估原始字符串,因为它不匹配。
如果您不希望实用方法创建 FindResult
实例,只需使用直接的 static
方法即可。
然而,这是过早优化的典型案例。 Pattern.compile
调用创建一个 Pattern
对象,加上一堆表示模式元素的内部节点对象, matcher
调用创建一个 Matcher
实例加上数组来保存组, toMatchResult
调用创建了另一个对象实例,当然,group(1)
调用不可避免地创建了一个表示结果的新字符串实例。
创建 FindResult
实例是这一行中成本最低的。如果您关心性能,如果您多次使用该模式,则保留 Pattern.compile
的结果,因为这是最昂贵的操作,并且 Pattern
实例是不可变且可共享的,如其文档中明确说明的.
当然,字符串方法 replaceFirst
和 replaceAll
没有什么神奇之处,但在幕后执行相同的步骤。
根据 this question,find
和 matches()
之间存在很大差异,但两者都以某种形式提供结果。
作为一种实用程序,toMatchResult
函数 returns 具有 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
也会抛出相同的异常...
当然需要使用 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.
上面的匹配逻辑不同该方法不需要实例字段即可工作。它可以只是一个静态助手:
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();
}
*/
}
}
toMatchResult()
方法returns之前匹配操作的状态,无论是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}.*", "");
该模式在实际匹配模式之前需要 .*?
并且在实际匹配模式之后需要 .*
,以消耗剩余的字符串并仅保留第一组作为其内容。需要注意的是,如果不存在匹配项,它将评估为原始字符串。
所以如果你想要 matches
而不是 find
语义,你可以使用
String expectingNoMatch = line.replaceFirst("^(a*b)a{3}$", "");
这将使用示例输入评估原始字符串,因为它不匹配。
如果您不希望实用方法创建 FindResult
实例,只需使用直接的 static
方法即可。
然而,这是过早优化的典型案例。 Pattern.compile
调用创建一个 Pattern
对象,加上一堆表示模式元素的内部节点对象, matcher
调用创建一个 Matcher
实例加上数组来保存组, toMatchResult
调用创建了另一个对象实例,当然,group(1)
调用不可避免地创建了一个表示结果的新字符串实例。
创建 FindResult
实例是这一行中成本最低的。如果您关心性能,如果您多次使用该模式,则保留 Pattern.compile
的结果,因为这是最昂贵的操作,并且 Pattern
实例是不可变且可共享的,如其文档中明确说明的.
当然,字符串方法 replaceFirst
和 replaceAll
没有什么神奇之处,但在幕后执行相同的步骤。