На мой взгляд код выполняет условия задачи.
Возможно быстрее было бы это условие реализовать через регулярные выражения, которых пока не было в обучающих материалах этого курса на javarush.
Над задачей работал несколько дней. Много раз исправлял код в процессе дебажинга - огромный плюс для практики.
Выполняет ли этот код условия задачи? Или что-то упустил?
Предполагаю, что могут найтись исключительные варианты.
package com.javarush.task.task19.task1918;
/*
Знакомство с тегами
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
String fileName = bfr.readLine();
bfr.close();
FileReader fileReader = new FileReader(fileName);
ArrayList<Character> charsList= new ArrayList<>();
char[] chars = new char[2000];
while (fileReader.ready()) {
fileReader.read(chars);
for (char c : chars) {
if(c != '\r' && c != '\n') charsList.add(c);
}
}
fileReader.close();
ArrayList<String>stringsList = tagExtract(charsList, args[0]);
for (String s : stringsList) System.out.println(s);
}
private static ArrayList<String> tagExtract (ArrayList<Character> charsList, String searchingTag) {
ArrayList<String> stringsList = new ArrayList<>();//лист для вывода хранения всех тегов
StringBuilder stringBuilder = new StringBuilder();//собиратель нужных символов
String tag = searchingTag;//искомый тег
int tagLength = tag.length();//длина искомого тега
boolean write = false;//начали записывать, ещё не знаем, возможно нужная нам подстрока
int startWrite = -1;//старт записи с этого индекса в проверяемой строке (возможна пока ещё проверка необходимости записи ( и до fullWrite))
boolean fullWrite = false;//тег определили, точно записываем
int innerTags = 0;//Количество тегов. > 1 - вложенные искомые
int maxTags = 0;//максимальное количество искомых тегов. > 1 - вложенные
boolean exit = false;//проверяем необходимость окончания записи - закрывающий тег
String stringForExit = "</" + tag + ">";//строка - условие для выхода из записи
int startExit = -1;//начинаем выходить начиная с индекса ...
boolean innerTag = false;//флаг, что возможно начался внутренний тег
for (int i = 0; i < charsList.size(); i++) {//перебираем все предоставленные символы
char c = charsList.get(i);//очередной (текущий) символ - из всего перечня предоставленных символов - и присваиваем перемной c
if (c == '<' && !write && !fullWrite) {//если текущий символ - открывающая скобка тега...(write и fullWrite - чтобы при записи сюда не заходили
write = true;//ставим флаг, что начали записывать, ещё не уверены, что это начало нужной нам подстроки
startWrite = i;//запомним, с какого индекса начали писать
stringBuilder.append(charsList.get(i));//добавляем открывающую начальную скобку в записываемую строку
continue;//дальше на этой итерации делать нечего
}//блок проверки начала искомого тега - <span - дальше - fullWrite
if (write && !fullWrite) {//если только начали писать и ещё не уверены что это нужная нам подстрока...
char d = ' ';//вынесли переменную просто чтоб можно было блок трай-кеч
try { //...проверяем необходимость дальнейшей записи
d = tag.charAt(i - startWrite - 1);//берём очередной символ из искомой строки-тега
} catch (StringIndexOutOfBoundsException e) {
System.out.println("i: " + i);
throw e;
}
if (c == d) {//текущий (очередной) символ из главной (которую передали для разбора) строки сравниваем с очередным из искомой последовательности-тега
stringBuilder.append(charsList.get(i));//если символы совпадают - продолжаем писать
if (i - startWrite == tagLength) {//если уже записали (4 символа) - длину искомого тега span... - возможно пора переходить на fullWrite
if (stringBuilder.toString().substring(1).equals(tag)) {//если собранная на данный момент строка символов (StringBuilder) без самого первого символа (<)...
fullWrite = true;//флаг - точно записываем //...эквивалентна нашему искомоу тегу (span)...
maxTags = ++innerTags;//макс кол-тво тегов и текущее кол-во тегов
startWrite = -1;//освобождаем переменную, она нам пригодится при записи следующих тегов
write = false;//освободили флаг для дальнейшего использования
continue;
} else {
write = false;
stringBuilder = new StringBuilder();
}
}
}
else {
stringBuilder = new StringBuilder();
startWrite = -1;
write = false;
}
}
if (fullWrite) {//уверены, что это нужная нам подстрока. Точно записываем
stringBuilder.append(c);//записали очередной нужный нам символ в стрингбилдер
//возможен внутренний тег (и возможен не один) || нужно учесть, что символ '<' может быть началом нового тега, а может быть началом закрывающего тега
if (c == '<' && !innerTag && !exit) {//если точно пишем, возможно начинается новый внутренний искомый тег (вариант б) или закрывающий тег (вариант a))
//флаги для варианта б) - начало нового тега
innerTag = true;//флаг, что возможно начался внутренний тег
startWrite = i;//запоминаем, с какого индекса в главной строке (возможно) начался внутренний тег
//...выставили флаги для варианта б)
//флаги для варианта а) - начало выхода
exit = true;//на всякий случай выставим флаг - на следующей итерации узнаем точно
startExit = i + 1;//если что - начнём выходить со следующего символа (проверить необходимость этой переменной)
//...выставили флаги для варианта а)
continue;//дальше с '<' ловить нечего
}//если во время точной записи, предыдущий в основной последовательности символ был '<' - Проверим возможные варианты:
if (innerTag) { //...варианты... а) начало (второй символ '/') выхода; б) начало (второй символ's') нового тега; в) другой, не интересный нам тег
char d = ' ';
try {
d = tag.charAt(i - startWrite-1);//присвоили очередной символ искомого тега
} catch (StringIndexOutOfBoundsException e) {
System.out.println("i: " + i);
System.out.println("startWrite : " + startWrite);
System.out.println("d: " + d);
}
if (c == d) {//проверка варианта б) - новый тег. Является ли текущий символ первым символом имкомого тега - s
//проверяем на соответствие тегу для входа <span , и если что - увеличиваем счётчик внутренних тегов для выхода или снимаем флаг внутренних тегов
String currentString = stringBuilder.toString();//посмотрим на собранную к этому моменту строку
String checkString = currentString.substring(currentString.length() - 4);//проверять (сравнивать) будем только крайние 4 символа (нам нужно span)
if (checkString.equals(tag)) {//если крайние 4 символов собранной строки - span, то точно новый тег
maxTags = ++innerTags;//увеличили счётчики внутренних тегов
innerTag = false;//сняли флаг внутреннего тега - он ещё может пригодиться, если встретятся ещё внутренние теги
startWrite = -1;//освободили переменную
} //если подтвердился вариант б), ...
if(exit) {
exit = false;//...то вариант а) не подтверждается: текущий (второй) символ - не '/' - а значит это не начало закрывающего тега
startExit = -1;//обнуляем (определим необходимость этой переменной
}
continue;
} else { //вариант б) не подтверждается. Очередной (следующий после '<' символ - не 's'
innerTag = false;//снимаем флаг внутреннего тега
startWrite = -1;//обнуляем стартовый (для записи) индекс
}
if(c != '/') {//не подтверждается вариант a) . У нас не начало закрывающего тега
exit = false;//снимаем флаг на выход (окончание записи
startExit = -1;//обнуляем индекс начала выхода (проверим необходимость этой переменной
continue;
}
}//нижнее условие: если стоит флаг на выход и после начала отсчёта на выход (startExit) прошли 7 символов...(Возможно условие нужно сменить на нижний комментарий
if (exit) {
if(i == startExit + 1 && c != tag.charAt(0)) {
exit = false;
startExit = -1;
continue;
}
if(i == startExit + stringForExit.length() - 2) {//если у нас закрывающий тег </span> - этим условием (комментарий) возможно нужно уилить (в скобки)
innerTags--;//уменьшили счётчик внутренних тегов
exit = false;//сняли флаг выхода - он может ещё пригодиться
startExit = -1;
if (innerTags == 0) {//если нашли крайний закрывающий тег - результат запишем (зафиксируем, в том числе и вложенность)
if (maxTags > 1) {
// stringBuilder.append(maxTags);//метка, что в этой строке есть вложенные теги (возможна другая реализация)
maxTags = 0;//обнулем максимальное количество найденных внутренних тегов - переменная пригодится, если внутренние теги ещё будут встречасться. Рекрусия
//обрезаем в строке крайние <spam> </spam> и запускаем на рекруссию
//затем продумать механизм добавления полученных строк в список
String sourceString = stringBuilder.toString();
// System.out.println("sourceString.length(): " + sourceString.length());
// System.out.println("sourceString: " + sourceString);
String tempString = sourceString.substring(tagLength, sourceString.length() - tagLength - 3);
// System.out.println("tempString: " + tempString);
// System.out.println("tempString.length(): " + tempString.length());
ArrayList<Character> tempCharArr = new ArrayList<>();
for (int j = 0; j < tempString.length(); j++) {
tempCharArr.add(tempString.charAt(j));
}
// for (char ch : tempCharArr) System.out.print(ch);
ArrayList<String> tempStringsList = tagExtract(tempCharArr, tag);
boolean f = false;
for (String s : tempStringsList) {
if (!f) {
stringsList.add(sourceString);
f = true;
}
stringsList.add(s);
fullWrite = false;
stringBuilder = new StringBuilder();
}
continue;
}
stringsList.add(stringBuilder.toString());//добавили собранную строку в лист
write = false;//снимаем флаг записи
fullWrite = false;//снимаем флаг точной записи
startWrite = -1;//обнуляем индекс начального символа для записи
stringBuilder = new StringBuilder();//обновляем стрингбилдер
startExit = -1;//обнуляем индекс начала выхода
exit = false;//снимаем флаг выхода - уже вышли
}
}
}
}
}
return stringsList;
}
}