Java 当没有';匹配';方法被调用

Java 当没有';匹配';方法被调用,java,regex,illegalstateexception,Java,Regex,Illegalstateexception,TL;DR API背后的设计决策是什么 背景 有一种我没有预料到的行为,我找不到一个好的理由。API文档说明: 一旦创建,匹配器可用于执行三种不同类型的匹配操作: [...] 每个方法都返回一个布尔值,指示成功或失败。通过查询匹配器的状态,可以获得有关成功匹配的更多信息 API文档进一步说明的是: 匹配器的显式状态最初未定义;在成功匹配之前尝试查询其中的任何部分将导致引发IllegalStateException 示例 String s = "foo=23,bar=42"; Pattern p

TL;DR

API背后的设计决策是什么

背景

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

一旦创建,匹配器可用于执行三种不同类型的匹配操作: [...] 每个方法都返回一个布尔值,指示成功或失败。通过查询匹配器的状态,可以获得有关成功匹配的更多信息

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"));
(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"));
String s=“foo=23,bar=42”;
模式p=Pattern.compile(“foo=(?[0-9]*),bar=(?[0-9]*)”;
匹配器匹配器=p.Matcher(s);
matcher.matches();//(2)
System.out.println(matcher.group(“foo”);
System.out.println(匹配器组(“bar”);
将调用添加到at
(2)
会将
匹配器设置为调用
组()的正确状态

问题,可能不是建设性的

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"));

为什么这个API是这样设计的?当使用
模式匹配器(字符串)
构建
匹配器时,为什么不自动匹配呢?

这是预期的,并且有文档记录

原因是
.matches()
返回一个布尔值,指示是否存在匹配项。如果存在匹配项,则可以有意义地调用
.group(…)
。否则,如果没有匹配项,则调用
.group(…)
没有意义。因此,在调用
matches()
之前,不应允许您调用
.group(…)

使用匹配器的正确方法如下所示:

Matcher m = p.matcher(s);
if (m.matches()) {
  ...println(matcher.group("foo"));
  ...
}

您需要检查
matcher.matches()
的返回值。当找到匹配项时,它将返回
true
,否则返回
false

if (matcher.matches()) {
    System.out.println(matcher.group("foo"));
    System.out.println(matcher.group("bar"));
}
如果
matcher.matches()
没有找到匹配项,并且您调用
matcher.group(…)
,您仍然会得到一个
非法状态异常。这正是文档所说的:

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


matcher.match()
返回
false
时,没有找到成功的匹配,并且通过调用例如
group()

来获取匹配信息没有多大意义实际上,您误解了文档。再看一看你引用的声明:-

在成功匹配之前尝试查询其任何部分将导致 要引发的非法状态异常

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

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

 - 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());
}
Matcher matcher = pattern.matcher(s);

   // Finds all the matches until found by moving the `matcher` forward
while(matcher.find()) {
    System.out.println(matcher.group());
}
但是,如果您想打印任何进一步的匹配,因为一个模式可以在一个字符串中匹配多次,那么应该有一种方法告诉匹配者找到下一个匹配。但是
null
检查将无法做到这一点。为此,您必须向前移动匹配器以匹配下一个字符串。因此,在
Matcher
类中定义了各种方法来实现这一目的。
matcher.find()
方法匹配字符串,直到找到所有匹配项

还有其他方法,
以不同的方式匹配
字符串,这取决于您希望如何匹配。因此,它最终由
Matcher
类对字符串进行
匹配
Pattern
类只创建一个要匹配的
模式。如果
Pattern.matcher()
match
该模式,那么必须有某种方法来定义各种
match
方法,因为
匹配可以有不同的方式。因此,需要
Matcher

事实上是这样的:-

// 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());
}
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个匹配项,则第一种方式将只打印第一个匹配项,而第二种方式将打印所有匹配项,方法是向前移动
匹配器以匹配下一个模式

我希望这能说明问题

类的文档描述了它提供的三种方法的使用,其中说明:-

通过调用模式的匹配器,从模式创建匹配器 方法。一旦创建,匹配器就可以用来执行三种不同的操作 匹配操作的种类:

  • matches方法尝试匹配整个输入序列 与模式相反

  • lookingAt方法
    Pattern p = new Pattern("([a-z]=([0-9]+);)+");
    Matcher m = p.matcher("a=1;b=2;x=3;");
    m.matches();
    System.out.println(m.group(2)); // Only matches value for x ('3') - not the other values