[LeetCode] Tag Validator

591. Tag Validator

Given a string representing a code snippet, implement a tag validator to parse the code and return whether it is valid.

A code snippet is valid if all the following rules hold:

  1. The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
  2. A closed tag (not necessarily valid) has exactly the following format : <TAG_NAME>TAG_CONTENT</TAG_NAME>. Among them, is the start tag, and is the end tag. The TAG_NAME in start and end tags should be the same. A closed tag is valid if and only if the TAG_NAME and TAG_CONTENT are valid.
  3. A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME is invalid.
  4. A valid TAG_CONTENT may contain other valid closed tags, cdata and any characters (see note1) EXCEPT unmatched <, unmatched start and end tag, and unmatched or closed tags with invalid TAG_NAME. Otherwise, the TAG_CONTENT is invalid.
  5. A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice versa. However, you also need to consider the issue of unbalanced when tags are nested.
  6. A < is unmatched if you cannot find a subsequent >. And when you find a < or </, all the subsequent characters until the next > should be parsed as TAG_NAME (not necessarily valid).
  7. The cdata has the following format : <![CDATA[CDATA_CONTENT]]>. The range of CDATA_CONTENT is defined as the characters between <![CDATA[ and the first subsequent ]]>.
  8. CDATA_CONTENT may contain any characters. The function of cdata is to forbid the validator to parse CDATA_CONTENT, so even it has some characters that can be parsed as tag (no matter valid or invalid), you should treat it as regular characters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
bool helperTag(string& s, int& p) {
int i = p;
string tag = parseTag(s,i);
if(tag == "") return false;
if(!helperContent(s,i)) return false;
int j = i + tag.length() + 3;
if(j > s.length() or s.substr(i,j-i) != "</" + tag + ">") return false;
p = j;
return true;
}
string parseTag(string& s, int& l) {
if(s[l] != '<') return "";
int r = s.find('>',l);
if(r == string::npos or r - 1 - l < 1 or 9 < r - 1 - l) return "";
string tag = s.substr(l+1,r-1-l);
for(auto& ch : tag) if(!isupper(ch)) return "";
l = r + 1;
return tag;
}
bool helperContent(string& s, int& p) {
int i = p;
while(i < s.length()) {
if(!helperText(s,i) and !helperCData(s,i) and !helperTag(s,i)) break;
}
p = i;
return true;
}
bool helperText(string& s, int& p) {
int i = p;
while(p < s.length() and s[p] != '<') p++;
return i != p;
}
bool helperCData(string& s, int& p) {
if(s.find("<![CDATA[",p) != p) return false;
int r = s.find("]]>", p);
if(r == string::npos) return false;
p = r + 3;
return true;
}
public:
bool isValid(string code) {
int p = 0;
return helperTag(code, p) and p == code.length();
}
};
Author: Song Hayoung
Link: https://songhayoung.github.io/2022/08/01/PS/LeetCode/tag-validator/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.