Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Solution(object):
- def isValid(self, code):
- self.pos = 0
- def eat_tag():
- start_pos = self.pos
- while self.pos < len(code) and code[self.pos] != '>':
- self.pos += 1
- self.pos += 1
- tag = code[start_pos:self.pos]
- return tag
- def eat_cdata():
- begin_len = len("<![CDATA[")
- end = "]]>"
- end_len = len(end)
- start_pos = self.pos
- self.pos += begin_len
- while self.pos + end_len < len(code) and code[self.pos:self.pos+end_len] != end:
- self.pos += 1
- self.pos += end_len
- cdata = code[start_pos:self.pos]
- return cdata
- def validate_open_tag(tag):
- if len(tag) > len('<>') + 9 or len(tag) < len('<>') + 1:
- return False
- elif tag[0] != '<' or tag[-1] != '>':
- return False
- return all(ch.isupper() for ch in tag[1:-1])
- def validate_close_tag(tag):
- if len(tag) > len('</>') + 9 or len(tag) < len('</>') + 1:
- return False
- elif tag[:2] != '</' or tag[-1] != '>':
- return False
- return all(ch.isupper() for ch in tag[2:-1])
- def validate_cdata(cdata):
- begin = "<![CDATA["
- end = "]]>"
- if len(cdata) < len(begin) + len(end):
- return False
- elif cdata[:len(begin)] != begin:
- return False
- elif cdata[len(cdata)-len(end):] != end:
- return False
- return True
- def validate_start_matches_end(start_tag, end_tag):
- if len(start_tag) != len(end_tag)-1:
- return False
- return start_tag[1:-1] == end_tag[2:-1]
- first_tag = eat_tag()
- if not validate_open_tag(first_tag):
- return False
- tag_stack = [first_tag]
- while self.pos < len(code) and tag_stack:
- peek = code[self.pos:self.pos+2] if self.pos+1 < len(code) else None
- if peek == '<!':
- cdata = eat_cdata()
- if not validate_cdata(cdata):
- return False
- elif peek == '</':
- close_tag = eat_tag()
- if not validate_close_tag(close_tag):
- return False
- elif not tag_stack:
- return False
- open_tag = tag_stack.pop()
- if not validate_start_matches_end(open_tag, close_tag):
- return False
- elif code[self.pos] == '<':
- open_tag = eat_tag()
- if not validate_open_tag(open_tag):
- return False
- tag_stack.append(open_tag)
- else:
- self.pos += 1
- return not tag_stack and self.pos >= len(code)
- """
- :type code: str
- :rtype: bool
- The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
- A closed tag (not necessarily valid) has exactly the following format : <TAG_NAME>TAG_CONTENT</TAG_NAME>. Among them, <TAG_NAME> is the start tag, and </TAG_NAME> 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.
- A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME is invalid.
- 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.
- 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.
- 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).
- 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 ]]>.
- 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.
- """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement