StringTokenizer
Хотя он не является частью библиотеки ввода/вывода, StringTokenizer имеет во многом сходную функциональность, что и описанный здесь StreamTokenizer.
StringTokenizer возвращает значащие элементы из строки по одной. Эти значащие элементы являются последовательностью символов, разделенных символами табуляции, пробелами и символами перевода строки. Таким образом, значащими элементами строки “Куда делась моя кошка?” являются “Куда”, “делась”, “моя” и “кошка?”. Как и в случае StreamTokenizer, вы можете настроить StringTokenizer, чтобы он разбивал ввод любым способом, который вам нужен, но с помощью StringTokenizer вы можете сделать это, передав второй аргумент в конструктор, который имеет тип String и является разделителем, который вы хотите использовать. В общем, если вам нужна большая изощренность, используйте StreamTokenizer.
Вы запрашиваете у объекта StringTokenizer следующий значащий элемент строки, используя метод nextToken( ), который возвращает либо следующий значащий элемент, либо пустую строку, которая указывает, что более элементов не осталось.
В качестве примера рассмотрим программу, которая выполняет ограниченный анализ предложения, ища ключевые фразы, указывающие на выражения счастья или огорчения.
//: c11:AnalyzeSentence.java
// Поиск определенных последовательностей в предложении.
import java.util.*;
public class AnalyzeSentence { public static void main(String[] args) { analyze("I am happy about this"); analyze("I am not happy about this"); analyze("I am not! I am happy"); analyze("I am sad about this"); analyze("I am not sad about this"); analyze("I am not! I am sad"); analyze("Are you happy about this?"); analyze("Are you sad about this?"); analyze("It's you! I am happy"); analyze("It's you! I am sad"); } static StringTokenizer st; static void analyze(String s) { prt("\nnew sentence >> " + s); boolean sad = false; st = new StringTokenizer(s); while (st.hasMoreTokens()) { String token = next(); // Поиск идет до тех пор, пока вы
// не найдете одну из двух начальных элементов:
if(!token.equals("I") && !token.equals("Are")) continue; // В начала цикла while
if(token.equals("I")) { String tk2 = next(); if(!tk2.equals("am")) // Должно быть после Я
break; // Выход из цикла while
else { String tk3 = next(); if(tk3.equals("sad")) { sad = true; break; // Выход из цикла while
} if (tk3.equals("not")) { String tk4 = next(); if(tk4.equals("sad")) break; // Leave sad false
if(tk4.equals("happy")) { sad = true; break; } } } } if(token.equals("Are")) { String tk2 = next(); if(!tk2.equals("you")) break; // Должно быть после Are
String tk3 = next(); if(tk3.equals("sad")) sad = true; break; // Выход из цикла while
} } if(sad) prt("Sad detected"); } static String next() { if(st.hasMoreTokens()) { String s = st.nextToken(); prt(s); return s; } else
return ""; } static void prt(String s) { System.out.println(s); } } ///:~
Анализ происходит для каждой строки, происходит вход в цикл while и из строки извлекается значащий элемент. Обратите внимание, что первая инструкция if, которая командует continue (вернуться назад к началу цикла и начать его заново), если значащий элемент не является ни словом "I", ни “Are”. Это означает, что будут извлекаться значащие элементы до тех пор, пока не будет найдено “I” или “Are”. Вы можете решить, что нужно использовать == вместо метода equals( ), но этот оператор не будет работать корректно, так как == сравнивает значения ссылок, а метод equals( ) сравнивает содержимое.
Логика оставшейся части метода analyze( ) заключается в поиске шаблона, с которого начинается фраза “I am sad”, “I am not happy” или “Are you sad?”. Без использования инструкции break этот код был бы еще грязнее, чем он есть. Вы должны знать, что типичный синтаксический анализатор (это примитивный пример одного из них) обычно имеет таблицу таких значащих элементов и часть кода, проходящую по всем состояниям таблицы, после чтения каждого элемента.
Вы должны думать, что StringTokenizer является стенографическим упрощением для определенного вида StreamTokenizer. Однако если вы имеете String, которую вы хотите разбить на элементы, StringTokenizer является слишком ограниченным, все, что вам нужно сделать - это перевести строку в StringBufferInputStream, а затем использовать его для создания более мощного StreamTokenizer.