首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调用“匹配”方法时Matcher抛出IllegalStateException的基本原理

调用“匹配”方法时Matcher抛出IllegalStateException的基本原理
EN

Stack Overflow用户
提问于 2012-10-16 09:26:15
回答 6查看 10.2K关注 0票数 32

TL;博士

Matcher的API背后的设计决策是什么?

背景

Matcher有一种我没有预料到的行为,我找不到一个很好的理由。API文档说:

创建之后,matcher可以用于执行三种不同的匹配操作:.这些方法中的每一个都返回一个布尔值,指示成功或失败。查询匹配程序的状态可以获得有关成功匹配的更多信息。

API文档进一步指出的是:

匹配器的显式状态最初是未定义的;在成功匹配之前尝试查询其任何部分将导致抛出IllegalStateException。

示例

代码语言:javascript
复制
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"));

此代码抛出一个

代码语言:javascript
复制
java.lang.IllegalStateException: No match found

(1)。为了解决这个问题,有必要调用matches()或其他将Matcher带入允许group()的状态的方法。以下工作:

代码语言:javascript
复制
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)时自动匹配?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-10-16 09:33:28

实际上,你误解了文件。再看一看你引用的声明:

在成功匹配之前尝试查询其中的任何部分将导致抛出IllegalStateException。

如果没有找到匹配项,matcher可能会在访问IllegalStateException时抛出matcher.group()

因此,您需要使用以下测试来实际启动匹配过程:-

代码语言:javascript
复制
 - matcher.matches() //Or
 - matcher.find()

以下代码:-

代码语言:javascript
复制
Matcher matcher = pattern.matcher();  

只需创建一个matcher实例。这实际上与字符串不匹配。即使有一场成功的比赛。因此,您需要检查以下条件,以检查是否匹配成功:

代码语言:javascript
复制
if (matcher.matches()) {
    // Then use `matcher.group()`
}

如果if中的条件返回false,这意味着没有匹配。因此,如果您使用matcher.group()而不检查此条件,则如果找不到匹配项,则将得到IllegalStateException

假设,如果Matcher是按照您所说的方式设计的,那么您必须执行null检查来检查是否找到匹配项,然后调用matcher.group(),如下所示:-

按你认为应该做的方式做:-

代码语言:javascript
复制
// 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类上对字符串执行matchingPattern类只创建要匹配的pattern。如果Pattern.matcher()match模式,那么就必须有某种方法来定义match的各种方式,因为matching可以是不同的方式。因此,出现了Matcher类的需求。

所以,实际上是这样的:-

代码语言:javascript
复制
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可用于执行三种不同类型的匹配操作:

  • match方法尝试将整个输入序列与模式匹配。
  • lookingAt方法尝试将输入序列与模式匹配,从开头开始。
  • find方法扫描输入序列,寻找与模式匹配的下一个子序列。

不幸的是,我还没有找到任何其他官方消息来源,明确地说出了这个问题的原因和方法。

票数 37
EN

Stack Overflow用户

发布于 2012-10-22 01:39:19

我的回答与罗希特·贾恩非常相似,但也包括了一些理由,为什么“额外”的一步是必要的。

java.util.regex实现

这句话:

代码语言:javascript
复制
Pattern p = Pattern.compile("foo=(?<foo>[0-9]*),bar=(?<bar>[0-9]*)");

导致分配一个新的模式对象,并在内部存储一个表示RE信息的结构,例如字符、组、序列、贪婪与非贪婪、重复等等的选择。

这种模式是无状态的,是不可变的,因此它可以被重用,是多目标的,并且可以很好地优化。

台词:

代码语言:javascript
复制
String s = "foo=23,bar=42";
Matcher matcher = p.matcher(s);

PatternString返回一个新的String对象--一个尚未读取字符串的对象。Matcher实际上只是一个状态机的状态,其中状态机是Pattern

可以通过使用以下API在匹配过程中逐步执行状态机来运行匹配:

  • lookingAt():尝试将输入序列与模式匹配,从开头开始
  • find():扫描输入序列,寻找与模式匹配的下一个子序列。

在这两种情况下,可以使用start()end()group()方法读取中间状态。

这种方法的好处

为什么会有人想要完成解析呢?

  1. 从量化大于1的组(即重复多次并最终匹配不止一次的组)获取值。例如,在下面解析变量赋值的平凡RE中: 模式p=新模式(“(a=(0-9+);)+”;Matcher m= p.matcher("a=1;b=2;x=3;");m.matches();System.out.println(m.group(2));//只匹配x ('3')的值-而不是其他值。 请参阅“组和捕获”中的“组名称”一节,即JavaDoc on 模式
  2. 开发人员可以使用RE作为雷克萨斯,开发人员可以将词汇标记绑定到解析器。实际上,这对于简单的域语言是有效的,但是正则表达式可能并不适合于一种成熟的计算机语言。编辑--这在一定程度上与前面的原因有关,但是创建处理文本的解析树通常比先对所有输入进行词法更容易,效率更高。
  3. (对于勇敢的人来说),您可以调试REs并找出哪些子序列不匹配(或匹配不正确)。

但是,在大多数情况下,您不需要在匹配过程中逐步执行状态机,因此有一种方便的方法(matches)来运行模式匹配以完成匹配。

票数 6
EN

Stack Overflow用户

发布于 2012-10-20 08:17:08

如果匹配器将自动匹配输入字符串,这将是浪费精力的,以防您希望找到模式的。

matcher可以用于检查模式是否matches()输入字符串,也可以用于find()输入字符串中的模式(甚至重复查找所有匹配的子字符串)。在调用这两个方法之一之前,matcher不知道要执行什么测试,因此它不能给出任何匹配的组。即使您确实调用了这些方法之一,调用也可能失败--没有找到模式--在这种情况下,对group的调用也必须失败。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12911504

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档