I have solved a task which takes input in a unique markup language. In this language each element consists of a starting and closing tag. Only starting tags can have attributes. Each attribute has a corresponding name and value.
For example:
<tag-name attribute1-name = "Value" attribute2-name = "Value2" ... >
A closing tag follows this format:
</tag-name>
The tags may also be nested. For example:
<tag1 value = "HelloWorld"> <tag2 name = "Name1"> </tag2> </tag1>
Attributes are referenced as:
tag1~value tag1.tag2~name
The source code of the markup language is given in n
lines of input, the number of attribute references or queries is q
.
I am seeking any improvements to my code and any bad practices I may be using.
#include <vector> #include <iostream> using namespace std; typedef vector < string > VS; typedef vector < VS > VVS; //Takes numberOfLines of input and splits the lines into strings VS Split(int numberOfLines) { VS myVec; string x; for (int i = 0; i < numberOfLines; i++) { getline(cin, x); string::size_type start = 0; string::size_type end = 0; while ((end = x.find(" ", start)) != string::npos) { myVec.push_back(x.substr(start, end - start)); start = end + 1; } myVec.push_back(x.substr(start)); } return myVec; } //removes unnecessary characters in this case they are: " , // > (if it is the final element of the tag), and " string Remove(string s) { string c = s; c.erase(c.begin()); auto x = c.end() - 1; if ( * x == '>') { c.erase(x); x = c.end() - 1; } c.erase(x); return c; } int main() { VS HRML, attributes, values, t, validTags; VVS Tags, ValidAttributes, ValidValues; int n, q; cin >> n >> q; HRML = Split(n); //does the heavy lifting for (int i = 0; i < HRML.size(); i++) { string x = HRML[i]; //checks if x contains the beginning of the starting tag if (x[0] == '<' && x[1] != '/') { //checks if x contains the end of the starting tag if (x[x.size() - 1] == '>' && x[1] != '/') { ValidAttributes.push_back(attributes); attributes.clear(); ValidValues.push_back(values); values.clear(); } auto c = x.end() - 1; if ( * c == '>') { x.erase(c); } x.erase(x.begin()); t.push_back(x); Tags.push_back(t); } // checks if x contains the end of the starting tag if (x[x.size() - 1] == '>' && x[1] != '/') { ValidAttributes.push_back(attributes); attributes.clear(); ValidValues.push_back(values); values.clear(); } //checks if x contains the ending tag else if (x[1] == '/') { x.erase(x.begin()); x.erase(x.begin()); x.erase(x.end() - 1); for (int i = 0; i < t.size(); i++) { if (x == t[i]) { t.erase(t.begin() + i); } } } //checks to see if an attribute has been assigned a value else if (x == "=") { attributes.push_back(HRML[i - 1]); values.push_back(Remove(HRML[i + 1])); } } string x = ""; //makes valid(user-usable) tags from all the tags // passed into vector<string> Tags for (int i = 0; i < Tags.size(); i++) { for (int j = 0; j < Tags[i].size(); j++) { if (Tags[i].size() > 1) { string begin = Tags[i][j] + '.'; x += begin; if (j == (Tags[i].size() - 1)) { x.erase(x.end() - 1); validTags.push_back(x + '~'); x = ""; } } else { validTags.push_back(Tags[i][0] + '~'); } } } //iterates through each query given by the user and checks if it is valid for (int i = 0; i < q + 1; i++) { string output = ""; if (i == 0) { string x; getline(cin, x); } else { string x; getline(cin, x); int c = 0; for (int j = 0; j < validTags.size(); j++) { for (int p = 0; p < ValidAttributes[c].size(); p++) { if (x == validTags[j] + ValidAttributes[c][p]) { output = ValidValues[c][p]; /*if a valid attribute reference has been found then there is no need to check the rest of validAttribute[c] */ goto endOfLoop; } else { output = "Not Found!"; } } if (c < (ValidAttributes.size() - 1)) { c++; } } endOfLoop: cout << output << endl; } } return 0; }
goto
in your code. Most coding standards consider this bad just by itself. I would consider it bad only if you can't justify it. But there is no comment explaining why you need a goto.\$\endgroup\$