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;
}
gotoin 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\$