2011-01-25 4 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

Я не знаю, что этот код должен делать, но я думаю, вы должны иметь [аз] * вместо [аз] –

+0

хорошо, полный общий случай является следующим «4d8 - 1d4 + 20» для анализа в виде двух бросков кубика + константа. Там может быть больше рулонов кости, их может не быть, могут быть пробелы или нет. В нижней строке я хотел бы изменить маркеры «на лету» без каких-либо разделителей. Я также не хочу, чтобы меня перенаправляли на обычный поток нот записи в SO, потому что это не помогает мне со всеми этими функциями eval, которые они все используют. Я хочу построить дерево выражения костей. –

ответ

3

К сожалению, вы не можете использовать разделители со сканером класса 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)); 
} 
+0

Ну, хорошая идея, но я не могу построить язык с этим. Я имею в виду, что если я буду искать , то снова за он пропустит все , чтобы найти номер. Наверное, мне придется сделать свой собственный сканер для этого. –

+0

@ Frór: Это не сильно отличается от примера, который вы нам дали, за исключением того, что он работает с вашей спецификацией. Если, конечно, нет других деталей, которые вы оставили, что вам нужно. –

+0

Да, есть другие требования, которые я считал тривиальными.Теперь я думаю об удалении всего этого вопроса и воссоздании нового с полным обзором проблемы. –

1

Вы можете достичь этого, используя классы Pattern и Matcher. См. Пример this.

+0

Nope regex этого не сделает. См. Мой комментарий по вопросу. –

+2

Ваш комментарий не дает мне понять, почему идиома Pattern/Matcher недостаточна. –

+0

Извините, чтобы быть полным, я хочу что-то лучшее, что-то более податливое, чем регулярное выражение. Регулярное выражение, в моем случае, полностью перекидывает гибкость, которую я ожидаю. В любом случае, спасибо ! –

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"); 
Смежные вопросы