2011-01-25 87 views
3

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


这个问题想念太多的信息。因此,所有的答案都是有效的问题,但不是我的问题。

+0

我不知道这是什么代码是应该做的,但我想你应该有[AZ],而不是* [AZ] – 2011-01-25 21:17:09

+0

好吧,完整常见的情况是下面的“4D8 - 1D4 + 20”被解析为两个骰子+常量。可能会有更多的骰子滚动,可能没有,可能有空格或没有空格。底线是我想在没有任何分隔符的情况下即时更换标记。我也不想被重定向到SO里的通常的Dice符号线程,因为它不能帮助我使用所有这些eval函数。我想建立骰子表达式的树。 – 2011-01-25 21:44:36

回答

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

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

+0

不正则正则表达式不会这样做。在这个问题下看到我的评论。 – 2011-01-25 21:45:11

1

要使用扫描仪作为标记生成器,使用与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

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

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