没有分隔符的扫描器

问题描述 投票:0回答:5

我希望能够解析如下字符串:“123456abcd9876az45678”。 BNF是这样的:

number: ? definition of an int ?
word: letter { , letter }
expression: number { , word , number }

但是 java.util.scanner 类不允许我执行以下操作:

Scanner s = new Scanner("-123456abcd9876az45678");
System.out.println(s.nextInt());
while (s.hasNext("[a-z]+")) {
    System.out.println(s.next("[a-z]+"));
    System.out.println(s.nextInt());
}

理想情况下,这应该产生:

-123456
abcd
987
az
45678

我真的希望 java.util.Scanner 能帮助我,但看起来我必须创建自己的扫描仪。 Java API 中是否已经存在任何可以帮助我的东西?


问题遗漏了太多信息。因此,所有答案都对问题有效,但对我的问题无效。

java java.util.scanner
5个回答
3
投票

不幸的是,您不能在 Scanner 类 AFAIK 中不使用定界符。如果您希望忽略定界符,则需要使用这样做的方法,例如

findInLine()
findWithinHorizon()
。在你的情况下,
findWithinHorizion()
是合适的。

Scanner s = new Scanner("-123456abcd9876az45678");
Pattern num = Pattern.compile("[+-]?\\d+");
Pattern letters = Pattern.compile("[A-Za-z]+");
System.out.println(s.findWithinHorizon(num, 0));
String str;
while ((str = s.findWithinHorizon(letters, 0)) != null) {
    System.out.println(str);
    System.out.println(s.findWithinHorizon(num, 0));
}

3
投票

要将扫描仪用作标记器,请使用

findWithinHorizon
\G
仅从组开始(=当前位置)开始扫描。

支持空格的示例(根据评论中的要求):

Scanner scanner = new Scanner(input);
while (true) {
  String letters = scanner.findWithinHorizon("\\G\\s*\\[a-zA-Z]+", 0);
  if (letters != null) {
    System.out.println("letters: " + letters.trim());
  } else {
    String number = scanner.findWithinHorizon("\\G\\s[+-]?[0-9]+", 0);
    if (number != null) {
      System.out.println("number: " + number.trim());
    } else if (scanner.findWithinHorizon("\\G\\s*\\Z", 0) != null) {
      System.out.println("end");
      break;
    } else {
      System.out.println("unrecognized input");
      break;
    }
  }
}

在实际应用中,您可能应该预先编译模式。


1
投票

您可以使用 PatternMatcher 类来实现这一点。见这个例子。


0
投票

问这个问题已经有很长一段时间了,OP 可能不再对答案感兴趣了,但是可能有一个零长度定界符.

var s = new Scanner(new ByteArrayInputStream("(2e-3*(4000+5)-.2)".getBytes(StandardCharsets.UTF_8)));
s.useDelimiter("(?=[+\\-*/()])|(?<=[+\\-*/()])");
while (s.hasNext()) {
    System.out.print(s.next()+" ");
}

版画

( 2e - 3 * ( 4000 + 5 ) - .2 ) 

正则表达式技巧是:

  • (?=[+\\-*/()])
    表示零长度后跟
    +-*/()
    ,我不得不双转义
    -
    ;
  • (?<=[+\\-*/()])
    表示
    +-*/()
    之后的零长度;
  • 他们之间是
    |
    “或”

如您所见,浮点数

2e-3
被拆分为 3 个标记。


-1
投票

您可以将分隔符设置为无法匹配任何内容的模式,例如

Scanner s = ...
s.useDelimiter("(?!=a)a");
© www.soinside.com 2019 - 2024. All rights reserved.