TL;博士
Matcher的API背后的设计决策是什么?
背景
Matcher有一种我没有预料到的行为,我找不到一个很好的理由。API文档说:
创建之后,matcher可以用于执行三种不同的匹配操作:.这些方法中的每一个都返回一个布尔值,指示成功或失败。查询匹配程序的状态可以获得有关成功匹配的更多信息。
API文档进一步指出的是:
匹配器的显式状态最初是未定义的;在成功匹配之前尝试查询其任何部分将导致抛出IllegalStateException。
示例
String s = "foo=23,bar=42";
Pattern p = Pattern.compile("foo=(?<foo>[0-9]*),bar=(?<bar>[0-9]*)");
Matcher matcher = p.matcher(s);
System.out.println(matcher.group("foo")); // (1)
System.out.println(matcher.group("bar"));此代码抛出一个
java.lang.IllegalStateException: No match found在(1)。为了解决这个问题,有必要调用matches()或其他将Matcher带入允许group()的状态的方法。以下工作:
String s = "foo=23,bar=42";
Pattern p = Pattern.compile("foo=(?<foo>[0-9]*),bar=(?<bar>[0-9]*)");
Matcher matcher = p.matcher(s);
matcher.matches(); // (2)
System.out.println(matcher.group("foo"));
System.out.println(matcher.group("bar"));添加对matches() at (2)的调用将Matcher设置为调用group()的适当状态。
问题,可能不是建设性的
为什么这个API是这样设计的?为什么不在使用Matcher生成Patter.matcher(String)时自动匹配?
发布于 2012-10-16 09:33:28
实际上,你误解了文件。再看一看你引用的声明:
在成功匹配之前尝试查询其中的任何部分将导致抛出IllegalStateException。
如果没有找到匹配项,matcher可能会在访问IllegalStateException时抛出matcher.group()。
因此,您需要使用以下测试来实际启动匹配过程:-
- matcher.matches() //Or
- matcher.find()以下代码:-
Matcher matcher = pattern.matcher(); 只需创建一个matcher实例。这实际上与字符串不匹配。即使有一场成功的比赛。因此,您需要检查以下条件,以检查是否匹配成功:
if (matcher.matches()) {
// Then use `matcher.group()`
}如果if中的条件返回false,这意味着没有匹配。因此,如果您使用matcher.group()而不检查此条件,则如果找不到匹配项,则将得到IllegalStateException。
假设,如果Matcher是按照您所说的方式设计的,那么您必须执行null检查来检查是否找到匹配项,然后调用matcher.group(),如下所示:-
按你认为应该做的方式做:-
// Suppose this returned the matched string
Matcher matcher = pattern.matcher(s);
// Need to check whether there was actually a match
if (matcher != null) { // Prints only the first match
System.out.println(matcher.group());
}但是,如果您想要打印任何进一步的匹配,因为一个模式可以在一个字符串中匹配多次,因此应该有一种方法可以告诉匹配器找到下一个匹配。但是null检查不能做到这一点。为此,您必须将匹配器向前移动以匹配下一个字符串。因此,在Matcher类中定义了各种方法来满足这一目的。matcher.find()方法与字符串匹配,直到找到所有匹配项为止。
还有其他方法,即以不同的方式match字符串,这取决于您想要如何匹配。因此,最终在Matcher类上对字符串执行matching。Pattern类只创建要匹配的pattern。如果Pattern.matcher()要match模式,那么就必须有某种方法来定义match的各种方式,因为matching可以是不同的方式。因此,出现了Matcher类的需求。
所以,实际上是这样的:-
Matcher matcher = pattern.matcher(s);
// Finds all the matches until found by moving the `matcher` forward
while(matcher.find()) {
System.out.println(matcher.group());
}因此,如果在字符串中找到4个匹配项,您的第一个方法将只打印第一个匹配项,而第二个方法将通过将matcher向前移动以匹配下一个模式来打印所有匹配项。
我希望这说明得很清楚。
Matcher类的文档描述了它提供的三种方法的用法,即:-
matcher是通过调用模式的matcher方法从模式创建的。创建之后,matcher可用于执行三种不同类型的匹配操作:
不幸的是,我还没有找到任何其他官方消息来源,明确地说出了这个问题的原因和方法。
发布于 2012-10-22 01:39:19
我的回答与罗希特·贾恩非常相似,但也包括了一些理由,为什么“额外”的一步是必要的。
java.util.regex实现
这句话:
Pattern p = Pattern.compile("foo=(?<foo>[0-9]*),bar=(?<bar>[0-9]*)");导致分配一个新的模式对象,并在内部存储一个表示RE信息的结构,例如字符、组、序列、贪婪与非贪婪、重复等等的选择。
这种模式是无状态的,是不可变的,因此它可以被重用,是多目标的,并且可以很好地优化。
台词:
String s = "foo=23,bar=42";
Matcher matcher = p.matcher(s);为Pattern和String返回一个新的String对象--一个尚未读取字符串的对象。Matcher实际上只是一个状态机的状态,其中状态机是Pattern。
可以通过使用以下API在匹配过程中逐步执行状态机来运行匹配:
lookingAt():尝试将输入序列与模式匹配,从开头开始find():扫描输入序列,寻找与模式匹配的下一个子序列。在这两种情况下,可以使用start()、end()和group()方法读取中间状态。
这种方法的好处
为什么会有人想要完成解析呢?
但是,在大多数情况下,您不需要在匹配过程中逐步执行状态机,因此有一种方便的方法(matches)来运行模式匹配以完成匹配。
发布于 2012-10-20 08:17:08
如果匹配器将自动匹配输入字符串,这将是浪费精力的,以防您希望找到模式的。
matcher可以用于检查模式是否matches()输入字符串,也可以用于find()输入字符串中的模式(甚至重复查找所有匹配的子字符串)。在调用这两个方法之一之前,matcher不知道要执行什么测试,因此它不能给出任何匹配的组。即使您确实调用了这些方法之一,调用也可能失败--没有找到模式--在这种情况下,对group的调用也必须失败。
https://stackoverflow.com/questions/12911504
复制相似问题