Приложение StreamToken
В приложении StreamToken мы демонстрируем
использование класса StreamTokenizer для разбора
входного потока.
Вначале приложение запрашивает у пользователя
строку для разбора, записывая ее в файл. Затем
этот файл открывается для чтения буферизованным
потоком и разбирается на составные элементы.
Каждый такой элемент выводится в отдельной
строке, как это показано на рис. 4.
Рис. 4. Разбор входного потока в
приложении StreamToken
Обратите внимание, что в процессе разбора
значение 3.14 было воспринято как числовое, а 3,14 -
нет. Это потому, что при настройке разборщика мы
указали, что символ '.' является обычным.
Исходный текст приложения
Исходный текст приложения StreamToken представлен в
листинге 1.
Листинг 1. Файл StreamToken.java
import java.io.*;
public class StreamToken
{
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);
sOut = new String(bKbdInput, 0);
OutStream = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(
"output.txt")));
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());
}
}
}
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;
}
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);
|