【问题标题】:Scanner without delimiter不带分隔符的扫描仪
【发布时间】:2011-01-25 21:14:23
【问题描述】:

我希望能够解析如下字符串:“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 中是否已经存在任何可以帮助我的东西?


这个问题错过了太多信息。因此,所有答案都对问题有效,但对我的问题无效。

【问题讨论】:

  • 我不知道这段代码应该做什么,但我想你应该有 [a-z]* 而不是 [a-z]
  • 好的,完整的常见情况是以下“4d8 - 1d4+20”被解析为两个骰子掷骰 + 一个常数。可能有更多的骰子,可能没有,可能有空格或没有空格。底线是我想在没有任何分隔符的情况下即时更改标记。我也不想被重定向到 SO 中通常的骰子符号线程,因为它对他们都在使用的所有这些 eval 函数没有帮助。我想构建骰子表达式的树。

标签: java java.util.scanner


【解决方案1】:

不幸的是,您不能在 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));
}

【讨论】:

  • 嗯,好主意,但我无法用它构建语言。我的意思是,如果我搜索 然后再次搜索 它将跳过所有 以查找数字。我想我必须为此制作自己的扫描仪。
  • @Frór:它与您给我们的示例没有太大区别,只是它符合您的规范。当然,除非您遗漏了您需要的其他一些细节。
  • 是的,还有其他一些我认为微不足道的要求。我现在正在考虑删除整个问题并重新创建一个完整概述该问题的新问题。
【解决方案2】:

要将扫描器用作分词器,请使用findWithinHorizon\G 仅从组开始(= 当前位置)进行扫描。

支持空格的示例(根据 cmets 的要求):

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;
    }
  }
}

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

【讨论】:

    【解决方案3】:

    您可以使用PatternMatcher 类来实现此目的。请参阅this 示例。

    【讨论】:

    • 不,正则表达式不会这样做。请参阅我在问题下的评论。
    • 你的评论没有让我明白为什么 Pattern/Matcher 成语是不够的。
    • 抱歉,完整地说,我想要更好的东西,比正则表达式更具延展性的东西。就我而言,正则表达式完全过度杀伤了我期望的灵活性。还是谢谢你!
    【解决方案4】:

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

    Scanner s = ...
    s.useDelimiter("(?!=a)a");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-26
      相关资源
      最近更新 更多