1. Введение
В этом руководстве мы покажем, как преобразовать поток символов в маркеры с помощью класса Java StreamTokenizer .
2. StreamTokenizer
Класс StreamTokenizer
считывает поток посимвольно. Каждый из них может иметь ноль или более следующих атрибутов: пробел, буква, цифра, строковая кавычка или символ комментария.
Теперь нам нужно понять конфигурацию по умолчанию. У нас есть следующие типы персонажей:
Символы слов
: диапазоны от «a» до «z» и от «A» до «Z».Числовые символы
: 0,1,…,9Пробелы
: значения ASCII от 0 до 32.Символ комментария
: /Символы строковых кавычек
: ' и "
Обратите внимание, что концы строк обрабатываются как пробелы, а не как отдельные токены, а комментарии в стиле C/C++ по умолчанию не распознаются.
Этот класс обладает набором важных полей:
TT_EOF
— константа, указывающая на конец потокаTT_EOL
— константа, указывающая конец строкиTT_NUMBER
— константа, указывающая числовой токенTT_WORD
— константа, указывающая токен слова
3. Конфигурация по умолчанию
Здесь мы создадим пример, чтобы понять механизм StreamTokenizer .
Мы начнем с создания экземпляра этого класса, а затем вызовем метод nextToken()
, пока он не вернет значение TT_EOF
:
private static final int QUOTE_CHARACTER = '\'';
private static final int DOUBLE_QUOTE_CHARACTER = '"';
public static List<Object> streamTokenizerWithDefaultConfiguration(Reader reader) throws IOException {
StreamTokenizer streamTokenizer = new StreamTokenizer(reader);
List<Object> tokens = new ArrayList<Object>();
int currentToken = streamTokenizer.nextToken();
while (currentToken != StreamTokenizer.TT_EOF) {
if (streamTokenizer.ttype == StreamTokenizer.TT_NUMBER) {
tokens.add(streamTokenizer.nval);
} else if (streamTokenizer.ttype == StreamTokenizer.TT_WORD
|| streamTokenizer.ttype == QUOTE_CHARACTER
|| streamTokenizer.ttype == DOUBLE_QUOTE_CHARACTER) {
tokens.add(streamTokenizer.sval);
} else {
tokens.add((char) currentToken);
}
currentToken = streamTokenizer.nextToken();
}
return tokens;
}
Тестовый файл просто содержит:
3 quick brown foxes jump over the "lazy" dog!
#test1
//test2
Теперь, если бы мы распечатали содержимое массива, мы бы увидели:
Number: 3.0
Word: quick
Word: brown
Word: foxes
Word: jump
Word: over
Word: the
Word: lazy
Word: dog
Ordinary char: !
Ordinary char: #
Word: test1
Чтобы лучше понять пример, нам нужно объяснить поля StreamTokenizer.ttype
, StreamTokenizer.nval
и StreamTokenizer.sval
.
Поле ttype
содержит тип только что прочитанного токена. Это может быть TT_EOF
, TT_EOL
, TT_NUMBER
, TT_WORD
. Однако для маркера строки в кавычках его значением является значение ASCII символа кавычек. Более того, если токен представляет собой обычный символ, например '!'
, без атрибутов, то ttype
будет заполнен значением ASCII этого символа.
Затем мы используем поле sval
для получения токена, только если это TT_WORD
, то есть токен слова. Но если мы имеем дело с токеном строки в кавычках — скажем, «ленивым», —
то это поле содержит тело строки.
Наконец, мы использовали поле nval
для получения токена, только если это числовой токен, используя TT_NUMBER
.
4. Пользовательская конфигурация
Здесь мы изменим конфигурацию по умолчанию и создадим еще один пример.
Во- первых, мы собираемся установить несколько дополнительных символов слова, используя метод wordChars(int low, int hi)
. Затем мы сделаем символ комментария ('/') обычным и продвигаем "#"
как новый символ комментария.
Наконец, мы рассмотрим конец строки как символ токена с помощью метода eolIsSignificant(boolean flag)
.
Нам нужно только вызвать эти методы для объекта streamTokenizer
:
public static List<Object> streamTokenizerWithCustomConfiguration(Reader reader) throws IOException {
StreamTokenizer streamTokenizer = new StreamTokenizer(reader);
List<Object> tokens = new ArrayList<Object>();
streamTokenizer.wordChars('!', '-');
streamTokenizer.ordinaryChar('/');
streamTokenizer.commentChar('#');
streamTokenizer.eolIsSignificant(true);
// same as before
return tokens;
}
И здесь у нас есть новый вывод:
// same output as earlier
Word: "lazy"
Word: dog!
Ordinary char:
Ordinary char:
Ordinary char: /
Ordinary char: /
Word: test2
Обратите внимание, что двойные кавычки стали частью токена, символ новой строки больше не является пробельным символом, а является обычным символом и, следовательно, односимвольным токеном.
Кроме того, символы, следующие за символом «#», теперь пропускаются, а «/» является обычным символом.
Мы также можем изменить символ кавычки с помощью метода quoteChar(int ch)
или даже символы пробела, вызвав метод whitespaceChars( int low, int hi)
. Таким образом, можно выполнять дальнейшие настройки, вызывая методы StreamTokenizer
в различных комбинациях .
5. Вывод
В этом руководстве мы увидели, как разобрать поток символов на токены с помощью класса StreamTokenizer
. Мы узнали о механизме по умолчанию и создали пример с конфигурацией по умолчанию.
Наконец, мы изменили параметры по умолчанию и заметили, насколько гибок класс StreamTokenizer .
Как обычно, код можно найти на GitHub .