Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

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);
[Назад] [Содеожание] [Дальше]