Microsoft Visual J++. Создание приложений и аплетов на языке Java. Часть 2© Александр Фролов, Григорий ФроловТом 32, М.: Диалог-МИФИ, 1997, 288 стр. Приложение StreamTokenВ приложении StreamToken мы демонстрируем использование класса StreamTokenizer для разбора входного потока. Вначале приложение запрашивает у пользователя строку для разбора, записывая ее в файл. Затем этот файл открывается для чтения буферизованным потоком и разбирается на составные элементы. Каждый такой элемент выводится в отдельной строке, как это показано на рис. 2.6.
Рис. 2.6. Разбор входного потока в приложении StreamToken Обратите внимание, что в процессе разбора значение 3.14 было воспринято как числовое, а 3,14 - нет. Это потому, что при настройке разборщика мы указали, что символ ‘.’ является обычным. Исходный текст приложенияИсходный текст приложения StreamToken представлен в листинге 2.5. Листинг 2.5. Файл StreamToken\StreamToken.java
// =========================================================
// Разбор входного потока при помощи класса
// StreamTokenizer
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
// =========================================================
import java.io.*;
// =========================================================
// Класс StreamToken
// Главный класс приложения
// =========================================================
public class StreamToken
{
// -------------------------------------------------------
// main
// Метод, получающий управление при запуске приложения
// -------------------------------------------------------
public static void main(String args[])
{
// Выходной поток
DataOutputStream OutStream;
// Входной поток
DataInputStream InStream;
// Массив для ввода строки с клавиатуры
byte bKbdInput[] = new byte[256];
// Введенная строка, которая будет записана в поток
String sOut;
try
{
// Выводим строку приглашения
System.out.println("Enter string to parse...");
// Читаем с клавиатуры строку для записи в файл
System.in.read(bKbdInput);
// Преобразуем введенные символы в строку типа String
sOut = new String(bKbdInput, 0);
// Создаем выходной буферизованный поток данных
OutStream = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("output.txt")));
// Записываем строку sOut в выходной поток
OutStream.writeBytes(sOut);
// Закрываем выходной поток
OutStream.close();
// Создаем входной буферизованный поток данных
InStream = new DataInputStream(
new BufferedInputStream(
new FileInputStream("output.txt")));
// Создаем объект для разбора потока
TokenizerOfStream tos = new TokenizerOfStream();
// Выполняем разбор
tos.TokenizeIt(InStream);
// Закрываем входной поток
InStream.close();
System.out.println("Press <Enter> to terminate...");
System.in.read(bKbdInput);
}
catch(Exception ioe)
{
System.out.println(ioe.toString());
}
}
}
// =========================================================
// Класс TokenizerOfStream
// Класс для разбора входного потока
// =========================================================
class TokenizerOfStream
{
public void TokenizeIt(InputStream is)
{
// Создаем разборщик потока
StreamTokenizer stok;
// Временная строка
String str;
try
{
// Создаем разборщик потока
stok = new StreamTokenizer(is);
// Задаем режим исключения комментариев,
// записанных в стиле С++ (два символа '/')
stok.slashSlashComments(true);
// Указываем , что символ '.' будет обычным символом
stok.ordinaryChar('.');
// Запускаем цикл разбора потока,
// который будет завершен при достижении
// конца потока
while(stok.nextToken() != StreamTokenizer.TT_EOF)
{
// Определяем тип выделенного элемента
switch(stok.ttype)
{
// Если это слово, записываем его во
// временную строку
case StreamTokenizer.TT_WORD:
{
str = new String("\nTT_WORD >" + stok.sval);
break;
}
// Если это число, преобразуем его
// в строку
case StreamTokenizer.TT_NUMBER:
{
str = "\nTT_NUMBER >" +
Double.toString(stok.nval);
break;
}
// Если найден конец строки,
// выводим строку End of line
case StreamTokenizer.TT_EOL:
{
str = new String("> End of line");
break;
}
// Выводим прочие символы
default:
{
if((char)stok.ttype == '"')
{
str = new String("\nTT_WORD >" + stok.sval);
}
else
str = "> " +
String.valueOf((char)stok.ttype);
}
// Выводим на консоль содержимое временной строки
System.out.println(str);
}
}
catch(Exception ioe)
{
System.out.println(ioe.toString());
}
}
}
Описание исходного текста приложенияПосле ввода строки с клавиатуры и записи ее в файл через поток наше приложение создает входной буферизованный поток, как это показано ниже:
InStream = new DataInputStream(
new BufferedInputStream(
new FileInputStream("output.txt")));
Далее для этого потока создается разборщик, который оформлен в отдельном классе TokenizerOfStream, определенном в нашем приложении: TokenizerOfStream tos = new TokenizerOfStream(); Вслед за этим мы вызываем метод TokenizeIt, определенный в классе TokenizerOfStream, передавая ему в качестве параметра ссылку на входной поток: tos.TokenizeIt(InStream); Метод TokenizeIt выполняет разбор входного потока, отображая результаты разбора на консоли. После выполнения разбора входной поток закрывается методом close: InStream.close(); Самое интересное в нашем приложении связано, очевидно, с классом TokenizerOfStream, поэтому перейдем к его описанию. В этом классе определен только один метод TokenizeIt:
public void TokenizeIt(InputStream is)
{
. . .
}
Получая в качестве параметра ссылку на входной поток, он прежде всего создает для него разборщик класса StreamTokenizer: StreamTokenizer stok; stok = new StreamTokenizer(is); Настройка параметров разборщика очень проста и сводится к вызовам всего двух методов:
stok.slashSlashComments(true);
stok.ordinaryChar('.');
Метод slashSlashComments включает режим распознавания комментариев в стиле языка программирования С++, а метод ordinaryChar объявляет символ ‘.’ обычным символом. После настройки запускается цикл разбора входного потока, причем условием завершения цикла является достижение конца этого потока:
while(stok.nextToken() != StreamTokenizer.TT_EOF)
{
. . .
}
В цикле анализируется содержимое поля ttype, которое зависит от типа элемента, обнаруженного во входном потоке:
switch(stok.ttype)
{
case StreamTokenizer.TT_WORD:
{
str = new String("\nTT_WORD >" + stok.sval);
break;
}
case StreamTokenizer.TT_NUMBER:
{
str = "\nTT_NUMBER >" + Double.toString(stok.nval);
break;
}
case StreamTokenizer.TT_EOL:
{
str = new String("> End of line");
break;
}
default:
{
if((char)stok.ttype == '"')
str = new String("\nTT_WORD >" + stok.sval);
else
str = "> " + String.valueOf((char)stok.ttype);
}
}
На слова и численные значения мы реагируем очень просто - записываем их текстовое представление в рабочую переменную str типа String. При обнаружении конца строки в эту переменную записывается строка End of line. Если же обнаружен обычный символ, мы сравниваем его с символом кавычки. При совпадении в переменную str записывается содержимое поля sval, в котором находятся слова, обнаруженные внутри кавычек. Если же обнаруженный символ не является символом кавычки, он преобразуется в строку и записывается в переменную str. В заключении метод выводит строку str в стандартный поток вывода, отображая на консоли выделенный элемент потока: System.out.println(str); |


