为什么“hello\\s*world”不能匹配“hello world”?

9
为什么这段代码会抛出 InputMismatchException 异常?
Scanner scanner = new Scanner("hello world");
System.out.println(scanner.next("hello\\s*world"));

相同的正则表达式在http://regexpal.com/上匹配(使用\s代替\\s)。


2
http://regexpal.com/ 用于测试 JavaScript 正则表达式,而不是 Java 正则表达式。您可以尝试使用 http://www.fileformat.info/tool/regex.htm 来测试 Java 正则表达式。 - Marcelo
@Marcelo 我最喜欢的在线Java正则表达式测试工具:http://www.regexplanet.com/simple/ - Matt Ball
@Matt 谢谢,我已经收藏了,下次需要的时候可以用得上。 - Marcelo
5个回答

11
与Matcher相比,Scanner具有内置的字符串分词功能,默认分隔符是空格。因此,在匹配运行之前,您的“hello world”被分词为“hello”和“world”。如果在扫描之前将分隔符更改为不在字符串中的内容,例如:,则会进行匹配。
Scanner scanner = new Scanner("hello world");
scanner.useDelimiter(":");
System.out.println(scanner.next("hello\\s*world"));

但对于你的情况来说,似乎只需要使用Matcher

这是正确使用Scanner的一个例子:

   Scanner scanner = new Scanner("hello,world,goodnight,moon");
   scanner.useDelimiter(",");
   while (scanner.hasNext()) {
     System.out.println(scanner.next("\\w*"));
   }

输出结果将会是

hello
world
goodnight
moon

如果字符串是hello:world呢?!你不应该对输入内容做出任何假设 :S - Vincent Koeman
这与为 Navin 说明他的代码为什么不起作用有什么关系呢?我说过:“如果匹配,那就是它了:”,而不是“如果严格正确并适合生产使用,那就是它了:”。输入明显假定为“hello world”;) - Affe
你本可以设置一个空的分隔符,而不是使用“:”。 - Vincent Koeman
一个分隔符""将把字符串分解成" h "," e "," l "," l "," o "等等。我想任何一些任意的不可打印的控制字符都可以被使用,但如果您正在使用扫描器进行解析,则输入需要在某种程度上受到限制。 - Affe

2
默认扫描器的分隔符是空格,因此扫描器会看到两个元素helloworld。而hello\s+world不能匹配hello,因此会抛出NoSuchElement异常。

2

这些输入是有效的:

"C:\Program Files\Java\jdk1.6.0_21\bin\java"  RegexTest hello\s+world "hello      world"
'hello      world' does match 'hello\s+world'

以下是代码:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTest {

    public static void main(String[] args) {

        if (args.length > 0) {
            Pattern pattern = Pattern.compile(args[0]);

            for (int i = 1; i < args.length; ++i) {
                Matcher matcher = pattern.matcher(args[i]);
                System.out.println("'" + args[i] + "' does " + (matcher.matches() ? "" : "not ") + "match '" + args[0]  +"'");
            }
        }
    }

}

1

扫描器的构造函数接受一个可选的模式,用于将输入序列分割成标记。默认情况下,这是一个空格模式。

Scanner#next返回下一个标记,如果它与给定的模式匹配。换句话说,你传递给#next的模式可能默认不包含空格。

您可以调用#useDelimiter来配置扫描器以适应您的用例。


-1

Scanner类有一个默认的分隔符\\s+。如果你只想匹配hello\\s*world,只需调用scanner.useDelimiter("hello\\s*world")),然后使用scanner.next();

另外,你可以调用scanner.useDelimiter('任何(转义)字符,不会出现在你的文本中'),并使用scanner.next("hello\\s*world"))

顺便说一下,如果你想至少有一个空格,你需要使用+而不是*


这个不起作用。分隔符“”将其标记为 h e l l o ' ' w o r l d。 - Affe
我已经编辑过了 :) 你需要使用一些肯定不在你的输入中的字符。请注意,有些字符是特殊的正则表达式字符,你需要转义它们才能使用。我经常使用的一个安全字符是 #。 - Vincent Koeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接