Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

jab4-answer / Job4_FilterComments / src / job4 / Job4_FilterMultiLineComments

.java
Скачиваний:
11
Добавлен:
18.03.2015
Размер:
14.9 Кб
Скачать
/**
* Реализация поддержки загрузки с многострочными комментариями.
* Задание 4, начато в модуле Job4_FilterComments.java.
* Вынести в отдельный пакет tools и реализовать в класс MatrixUtils следующие
* методы, использованные в ЛР №2:
• static int[] readVector(InputStream stm, int size, CheckComment isComment)
для чтения вектора чисел из потока
здесь stm входной поток с данными (может иметь более подходящий тип, например, BufferedReader ),
size кол-во элементов в векторе,
isComment это интерфейс проверки является ли строка комментарием. Интерфейс имеет вид:
interface CheckComment {
boolean isComment(String data);
}

• static int[][] readMatrix(InputStreamstm, introws, intcols, CheckComment isComment)
для чтения матрицы из потока
здесь stm входной поток с данными,
rows, cols кол-во срок и столбцов матрицы,

• static StringBuilder getPrintViewVector(int[] vector)
для формирования текстового дампа для вектора – числа в одну строку

• static StringBuilder getPrintViewMatrix(int[][] matrix)
дляформированиядампа матрицы по строкам.

Выполнить лабораторную работу №2 с использованием функций нового пакета.
Все методы главного класса, кроме main, сделать НЕ статическими.
Интерфейс CheckComment реализовать внутренним классом.

Здесь, по сравнению с Job4_FilterComments, реализован костяк дополнительных заданий:
1) Комментарии в конце строки: если в строке встречается пара символов "//", то
начало строки до этих символов - данные, после них - комментарий.
(!) Это здесь сделано заменой метода интерфейса CheckComment.isComment на
новый CheckComment.removeComment, который способен изменять строку данных,
удаляя комментарии и незначащие пробелы.

2) Частичные комментарии внтутри строк, когда данные и комментарий могут
перемежаться, вида:
/ * коментарий внутри косых скобок * / реализовано здесь
(*коментарий внутри круглых скобок *) на самостоятельную работу
{ коментарий внутри фигурных скобок } на самостоятельную работу

3) Комментарии из п 2 могут быть многострочные, т.е. начинаться на одной строке,
а заканчиваться в другой (в любом её месте).
(!) Учесть, что в любой строке могу встречаться совместно разные виды
комментариев, причём неоднократно.
Например:
25 { комментарий 1 } -3 4 (* комментарий 2*) 32 // комментарий до конца строки.

* Вывод сформированный данным классом см файл data-Job4_FilterMultiLineComments.java.lst

*/

package job4;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import my.utils.MatrixUtils;
import my.utils.MatrixUtils.CheckComment;

public class Job4_FilterMultiLineComments {

/** файл для демонстрации чтения с пропуском комментариев */
final static String FILE_NAME = "data.txt";

/**
* Вводим дополнительный интерфейс-потомок чекера с дополнительным методом
* очистки состояния clear
*/
interface XCheckComment extends CheckComment {
// сбросить состояние объекта в нанчальное (вне комментария)
void clear();
}

// Основной тест
public static void main(String[] args) {
try {
/**
* (!) у MatrixUtils конструктор приватный и создание здесь невозможно
* (и не нужно, т.к. все его методы статические)
*/
// MatrixUtils utils = new MatrixUtils();

// буфер под формирование выходных результатов
final StringBuilder result = new StringBuilder();

try {
/**
* Инициализируем объект, который будем использовать для проверки комментариев
*/
final XCheckComment checkMultiLines = new XCheckMultiLineImpl();

/* Выполняем чтение из файла с разными стратегиями провеки комментариев ... */

// здесь "спотыкаемся" на входной строке
// ";// and this one too"
// т.к. в правиле по-умолчанию начало ";" не является комментарием
testReadTextFile( "\n\tпо правилам комментариев по-умолчанию...", FILE_NAME, null, result);

// здест всё в порядке - прочитается и вектор и матрица ...
testReadTextFile( "\n\tпо правилам многострочных комментариев ...", FILE_NAME, checkMultiLines, result);

} finally {
// отображаем на консоли результат
System.out.println(result.toString());
}
} catch (IOException ex) {
Logger.getLogger(Job4_FilterMultiLineComments.class.getName()).log(Level.SEVERE, null, ex);
}
}

/**
* Тестовая функция проверки чтения текстового файла с помощью заданного
* правила пропуска комментариев.
* @param title заголовок, для пояснения
* @param fileName имя читаемого файла
* @param checker объект, реализующий праила чтения комментариев
* @param result выходной буфер для получения читаемых данных
* @throws IOException
*/
private static void testReadTextFile( final String title,
final String fileName,
final XCheckComment checker,
final StringBuilder result)
throws IOException
{
final File loadingFile = new File(fileName);

result.append(String.format("\nЧитаем файл '%s' %s\n", loadingFile.getAbsoluteFile(), title));

final BufferedReader buf = new BufferedReader(new FileReader(loadingFile.getAbsoluteFile()));
try {
if (checker != null)
checker.clear(); // выполняем сброс, чтобы почитсить состояние после предыдущих проверок

/**
* вызываем чтение вектора из файла: передаём для функции чтения
* checkObj для проверки комментариев
*/
final int[] v = MatrixUtils.readVector(buf, 3, checker);

// выводим в буфер прочитанный вектор
MatrixUtils.printVector(result, "Прочитан вектор:\n", v);
result.append("\n");

final int rows = v[0], cols = v[1];
final int[][] matrix = MatrixUtils.readMatrix(buf, rows, cols, checker);
// выводим в буфер прочитанный вектор
MatrixUtils.printMatrix(result, "Прочитана матрица:\n", matrix);

result.append( String.format( "\n(*) %s: Ошибок нет\n", title));

} catch (Throwable ex) {
// здесь перехватываем все возможные имелючения в отладочных целях ...
// Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
// ex.printStackTrace(System.err);
result.append(String.format("Произошла ошибка (%s):\n%s\n", ex.getClass(), ex.getMessage()));
} finally {
buf.close();
}
}

/**
* пример прокси-класса для обёртывания производльной реализации CheckComment
*/
class Proxy implements CheckComment {
final CheckComment fld;

public Proxy(CheckComment fld) {
this.fld = fld;
}

@Override
public String removeComment(String data) {
// строку "особое значение" воспринимаем как комментарий
if (SPECIAL_VALUE.equalsIgnoreCase(data))
return null;

// теперь вызовем основной ...
String result = fld.removeComment(data);
// if (result != null && ... здесь можно проверить, а затем и изменить result нужным образом ...

return result;
}

private static final String SPECIAL_VALUE = "особое значение";
}

/**
* Реализация многострочных комментариев.
* Для каждой отдельной строки применяем посимвольное сканирование.
*/
static class XCheckMultiLineImpl implements XCheckComment {

private String curLine = null; // последняя (текущая) прочитанная строка
private int curPos = 0; // индекс первого необработанного символа внутри curLine
private boolean flagMultiLine = false; // true признак того, что был открыт многострочный комментарий '/*' или иной...

@Override
public void clear() {
this.flagMultiLine = false;
this.curPos = 0;
this.curLine = null;
}

@Override
public String removeComment(String data) {
this.curLine = data;
return scanLine(0);
}

/**
* Вернёт true, если текущая строка проверена до конца ...
* @return
*/
private boolean endOfLine() {
return (curLine == null) || (curLine.length() <= curPos);
}

/**
* Основная функция выкусывания комментария из curLine.
* Сделана рекурсивной, работает с внут переменными класса, так что это
* private-функция.
*/
private String scanLine(int from) {
this.curPos = from;
if (endOfLine()) { // в текущей строке больше уже нечего брать ...
return "";
}

// если находимся внутри многострочного комментария ...
if (flagMultiLine) {
// ждём конца открытого ранее комментария ...
final int closePos = curLine.indexOf("*/", this.curPos);
if (closePos == -1) { // в этой строке комментарий не закрывается -> пропуск всего остатка ...
this.curPos = this.curLine.length(); // пропуск до конца строки ...
return ""; // ничего нет в строке ...
}

// конец многострочного комментария ...
this.flagMultiLine = false;
// начинаем накопление после символов, закрывающих комментарий ...
this.curPos = closePos + 2;
}

// сканирование текущей строки до конца или начала нового комментария
final int istart = this.curPos;
scan: for (; this.curPos < this.curLine.length(); this.curPos++) {
switch (this.curLine.charAt(this.curPos)) {
case '/':
// проверяем следующий символ ...
if (this.curPos >= this.curLine.length())
// это последний символ в строке -> следующего нет
// -> это точно не начало комментария "/*" ...
continue; // for

/* проверка начала комментария вида "/* xxx" ... */
final boolean nextIsMultiLineOpen = this.curLine.charAt(this.curPos+1) == '*';
if (nextIsMultiLineOpen) {
this.flagMultiLine = true; // true, т.к. открыт многострочный комментарий '/*'...
// многострочный комментарий может продолжаться внутри строки,
// так что просто ждём окончание в текущей строке - рекурсия,
// + накапливаем текст...
return this.curLine.substring(istart, this.curPos) + scanLine(this.curPos + 2);
}

/* проверка начала комментария вида "// xxx" ... */
final boolean nextIsSlash = this.curLine.charAt(this.curPos+1) == '/';
if (!nextIsSlash) // это не двойной слеш - продолжаем ...
break; // переход "за" swicth
// здесь код сработает когда комментарий будет начинаться с '//'
// (!) тогда "проваливаемся" дальше в swicth ...

/* начало комментария "# xxx" или "; xxx" */
case '#':
case ';':
// тут вся часть строки до конца должна быть отброшена как комментарий,
// а часть строки от curPos до этого символа - данные ...
break scan; // for
} // switch
} // for
// вернуть строку от исходной позиции до предпоследней проверенной ...
final String result = this.curLine.substring(istart, this.curPos);
this.curPos = this.curLine.length(); // пропуск до конца строки ...
return result;
}

}
}
Соседние файлы в папке job4