【问题标题】:Java Scanner - Ignore Subsequent LettersJava 扫描器 - 忽略后续字母
【发布时间】:2016-02-16 16:57:50
【问题描述】:

我的程序需要接受整数、单个字符或一个特定的字符串(我将在此示例中使用"pear")。虽然它们中的每一个都可以用空格分隔,但应该没有必要。

目前,我依赖于Scanner 的解析代码如下所示:

Scanner scanner = new Scanner(System.in);

while (scanner.hasNext()) {
    if (scanner.hasNext("\\s+")) {
        // Ignore whitespace…

    } else if (scanner.hasNext("[-]?\\d+")) {
        // Get a number
        String nextNumberString = scanner.next("[-]?\\d+");
        // Process the string representing the number…

    } else if (scanner.hasNext("pear")) {
        scanner.next("pear");
        // Do something special…

    } else {
        // Get the next character
        Pattern oldDelimiter = scanner.delimiter();
        scanner.useDelimiter("");
        String nextCharAsString = scanner.next();
        scanner.useDelimiter(oldDelimiter);

        char nextCharacter = nextCharAsString.charAt(0);

        if (Character.isWhitespace(nextCharacter)) {
            // Ignore whitespace…
        } else {
            // Process character…
        }

    }
}

目前,我的程序可以毫无问题地接受123 d 456 r pear 这样的输入。但是,它也应该接受没有任何空格的相同输入 (123d456rpear),并以相同的方式解释它,并且使用我当前的代码,单个数字被错误地解释为字符。

我觉得原因可能是我正在使用的正则表达式。但是,将.* 添加到它们的末尾将导致解析所有后续字符以及我尝试解析的输入。例如,[-]?\d+.* 将尝试将整个123d456rpear 解析为一个数字,而我真的只想要123,剩下的留待以后解析。我还尝试将我想要的输入包装到一个组中,然后附加 ?{1},这也不起作用。

我也尝试过scanner.findInLine(),但在我的测试中,这似乎也不起作用。例如,当我尝试这样做时,pearpear 会导致无限循环,尽管我尝试跳过 pear 的第一个实例。

我还尝试将分隔符设置为"",就像我在提取单个字符时所做的那样(在这种情况下,它可以按预期工作)。但是,这会导致单独处理每个单独的数字,解析 123 而不是 123pear 也被解释为单个字符。

那么,有人可以帮我弄清楚我哪里出错了吗?这个问题出在我的正则表达式上吗?我使用了错误的方法吗?还是我误解了 Scanner 类的工作原理?

【问题讨论】:

  • 程序应该如何区分单个字符和像梨这样的字符串?
  • 通常,单个字符被解释为某种命令,但如果输入这个特殊字符串,我必须包含一个复活节彩蛋。这就是为什么我在解释之前检查这个特殊字符串的原因输入为单个字符。
  • @YassinHajaj 该字符串只是一个特定的魔术字符串,而不是一般的字符串。因此解析器优先解析字符串“pear”(如果可以找到),否则会读取单个字符,例如“pead”将被解析为“p”、“e”、“a”、“d”,但是“梨”将被解析为“梨”,“d”。
  • 没错,谢谢@IngoBürk

标签: java regex parsing java.util.scanner


【解决方案1】:

the individual digits are incorrectly interpreted as characters 因为 Scanner 的 hasNext 方法从delimiter 给定的令牌中提取令牌,默认为空格

来自 java 文档

扫描器使用分隔符模式将其输入分解为标记, 默认情况下匹配空格。然后生成的令牌可能是 使用各种 next 转换为不同类型的值 方法

因此提取了整个123d456rpear,它不是数字而是字符串

【讨论】:

  • 这可能是真的,但它并不能帮助我更接近所需的功能......
  • 据我了解,Scanner 类的想法是提取标记并丢弃分隔符。这就是阿努帕姆引用的。但是,如果您的输入中没有空格,您根本不想扔掉任何东西。所以 Scanner 可能是错误的类,或者只有 findInLine() 对您的问题有用。
【解决方案2】:

据我了解,Scanner 类的想法是提取标记并丢弃分隔符。但是你不想扔掉除了空格之外的任何东西。但是,您的输入中不需要空格。这是一个使用外部和内部扫描器的实现思路。外部标记在空格处 - 如果有的话。内部使用findInLine() 完全绕过分隔符。

查找内联

尝试查找从 指定的字符串,忽略分隔符。

public void scan(Scanner scanner) {
    while (scanner.hasNext()) {
        String next = scanner.next();
        System.out.println("opening inner scanner: " + next);
        Scanner innerScanner = new Scanner(next);
        do {
            next = innerScanner.findInLine("([-]?\\d+)|(pear)|([a-zA-Z])");
            if (next == null) {
                // Nothing useful in there
            } else if (next.equals("pear")) {
                System.out.println("pear");
            } else if (next.matches("[a-zA-Z]")) {
                System.out.println("char: " + next);
            } else {
                System.out.println("number: " + next);
            }
        } while (next != null);
        innerScanner.close();
    }
}

public void run() {
    scan(new Scanner("123 d 456 pear"));
    scan(new Scanner("123d456pear"));
}

run()方法的输出如下:

opening inner scanner: 123
number: 123
opening inner scanner: d
char: d
opening inner scanner: 456
number: 456
opening inner scanner: pear
pear
opening inner scanner: 123d456pear
number: 123
char: d
number: 456
pear

【讨论】:

  • 非常感谢!很抱歉响应缓慢,但我最终从这段代码向后工作,只使用一台扫描仪。感谢您的帮助!
  • 太棒了。您认为将您的单一扫描仪解决方案添加到问题或其他地方可能有用吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 2018-07-01
  • 2013-04-23
  • 2016-09-21
  • 1970-01-01
相关资源
最近更新 更多