Can anyone cast a more experience eye over this?
It works with many examples but it is timing out on the server.
I have use recursion for this solution and I've tried to make it as readable as possible.
Have I over engineered this?
package com.codegym.task.task19.task1918;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
public class Solution {
private static TreeMap<Integer, String> tags = new TreeMap<>();
private static char[] buffer;
private static String openTag;
private static String closeTag;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String filename = br.readLine();
br.close();
openTag = String.format("<%s>", args[0]);
closeTag = String.format("</%s>", args[0]);
getBuffer(filename); //populate buffer
tagFinder(0, 0);
printTags();
}
public static void tagFinder(int startPos, int openTags) {
int totalTagCount = openTags; //the number of tags currently open
int myOpeningTagCount = 0; //number of tags I have open
int myTagStartPoint = startPos; //my starting point
int nextTagStartPoint; //starting point fo any new matching tags for recursion
int myTagEndPoint = 0; //ending point when all my tags closed
boolean recordTag = false; //currently building a new tag to check?
boolean myFirstPass = true; //is this my first pass finding a matching tag?
String currentTag = "";
for (int i = startPos; i < buffer.length; i++) {
char tempChar = buffer[i];
if (tempChar == '<') { //begin building <tag> - used to check if tag needed or ignored
recordTag = true;
} else if (tempChar == '>') { //close <tag> ensure tag is full (>) stop recording further chars
currentTag = currentTag + tempChar;
recordTag = false;
if (tagOpenMatch(currentTag)) { //check if tag is an open match e.g. <tag> equals <tag>
totalTagCount++; //add one to overall tags open
myOpeningTagCount++; //add one to myOpenTag count
if (myFirstPass) { //if this is the first pass set the starting point for recording overall string then set first pass to false
myTagStartPoint = (i - currentTag.length()) + 1;
myFirstPass = false;
} else { //if not first pass then begin recursion pass to new method the start point of the new matching tag and current tags open
nextTagStartPoint = (i - currentTag.length()) + 1;
tagFinder(nextTagStartPoint, totalTagCount); // somewhere here needs recursion check logic for if current tag already being worked on (so don't call same twice).
}
currentTag = ""; //reset currentTag string to "" for the next tag search
} else if (tagCloseMatch(currentTag)) { //if the tag isn't a match for open tags check if it matches closed tags
currentTag = ""; //reset currentTag string to "" for next tag to be found
totalTagCount--; //reduce the total tag count
myOpeningTagCount--; //reduce myOpenTagCount by one
if (myOpeningTagCount == 0) {
myTagEndPoint = i;
}
} else {
currentTag = "";
}
}
if (recordTag) { //record current char to currentTag if we are currently building a tag to check
currentTag = currentTag + tempChar;
}
if (myOpeningTagCount == 0 && !myFirstPass) { //if I have all open tags closed and this is not my first pass then add my tag string to the map
String myCompleteTagString = "";
for (int j = myTagStartPoint; j < ((myTagEndPoint) + 1); j++) { //loop from myTagStartPoint to myEndPoint adding each char we find
myCompleteTagString = myCompleteTagString + buffer[j];
}
if (!tags.containsKey(myTagStartPoint)) {
tags.put(myTagStartPoint, myCompleteTagString); //add the tag to the map
}
if (totalTagCount > 0) { //if my tags are all closes but there are still some open then break the loop this closes this method/recursion and we go back to calling code (previous recursive)
break;
}
}
}
}
//pass in current tempTag and see if it matches the open tag of args e.g. <tag>
public static boolean tagOpenMatch(String tagInput) {
String tempTag = "";
String tagToFind = openTag;
for (char c : tagInput.toCharArray()) {
if (c == '\n' || c == '\r' || c == ' ') {
break;
} else if (c == '/') { //be sure not to return true for closed tag e.g. </tag>
return false;
}
tempTag = tempTag + c;
}
tempTag = tempTag.replaceAll("<|>", ""); //removes <> for comparisons
tagToFind = tagToFind.replaceAll("<|>", ""); //removes <> for comparisons
return tempTag.equals(tagToFind);
}
//pass in current tempTag and see if it matches the close tag of args e.g. </tag>
public static boolean tagCloseMatch(String tagInput) {
String tagToFind = closeTag;
return tagInput.equals(tagToFind);
}
//populate buffer
public static void getBuffer(String filename) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader(filename));
ArrayList<String> input = new ArrayList<>();
String s;
int charCount = 0;
while ((s = reader.readLine()) != null) {
s = s + "\n";
input.add(s);
charCount = charCount + s.length();
}
reader.close();
buffer = new char[charCount];
int fillCount = 0;
for (int i = 0; i < input.size(); i++) {
String tempLine = input.get(i);
for (int j = 0; j < tempLine.length(); j++) {
buffer[fillCount] = tempLine.charAt(j);
fillCount++;
}
}
}
//print tags
public static void printTags() {
if (!tags.isEmpty()) {
for (Map.Entry<Integer, String> pair : tags.entrySet()) {
String s = pair.getValue();
s = s.replaceAll("\n|\r", "");
System.out.println(s);
}
}
}
}