class ParseError(Exception): """Report an error parsing the document.""" def __init__(self, data): """Initialize a new exception with data about the error.""" self.data = data def __str__(self): """Return the error data as a string.""" return str(self.data)def parse(lines): """Take a 148ML document as input, and return a parsed version represented as a list of nested lists.""" print lines # Fill here! import stack #Variable new_lines is assigned as lines without "\n" new_lines = lines.replace("\n", "") #Variable lst_lines is assigned as a list of new_lines split at ">" lst_lines = new_lines.split(">") #Variables tag_stack & tag_checker are assigned empty stacks. An empty list #is added to tag_stack. tag_stack = stack.Stack() tag_stack.push([]) tag_checker = stack.Stack() #For every line in the list of lines: for line in lst_lines: line = line.strip() #Take white space off the front and end of the line. #If the line is an empty string, then it changes to " ". if line == "": line = " " #If line is made of letters: if line.isalpha(): #The current line is appended to the topmost object in tag_stack current_tag = tag_stack.pop() current_tag.append(line) tag_stack.push(current_tag) #Otherwise if a space is in line or the first character is a letter: elif " " in line or line[0].isalpha(): if " " in line: #If line has a space: #Variable temp_line is assigned a list of line split at " ". temp_line = line.split(" ") else: #Variable temp_line is assigned a list of line split with "<". i = line.find("<") temp_line = [line[:i], line[i:]] #For every piece of the line: for piece in temp_line: #If the piece is not an empty string: if piece != "": #If the piece is made of letters: if piece.isalpha(): #The piece is added to the topmost object in tag_stack. current_tag = tag_stack.pop() current_tag.append(piece) tag_stack.push(current_tag) #Otherwise if the first two characters are "</": elif piece[0:2] == "</": current_tag = tag_stack.pop() bit = "<" + piece[2:] + ">" #If the tag text is non alphabetic, raise an exception. if not piece[2:].isalpha(): raise ParseError("Tag is non alphabetical.") #Otherwise if current_tag isn't empty & first tag is #the opening tag for piece: elif current_tag != [] and current_tag[0] == bit: #End tag gets added to current tag then is added #to the lower layer. Otherwise raise exception. current_tag.append(piece + ">") new_tag = tag_stack.pop() new_tag.append(current_tag) tag_stack.push(new_tag) tag_checker.pop() else: raise ParseError("Tag not balanced.") #Otherwise if the first character is "<": elif piece[0] == "<": #If the rest of the piece is made of letters: if piece[1:].isalpha(): #Piece tag is added to tag_Stack & tag_checker #otherwise raise exception. tag_stack.push([piece + ">"]) tag_checker.push(piece + ">") else: raise ParseError("Tag is non alphabetical.") #Otherwise raise exception. elif not piece.isalpha() and not piece.isspace(): raise ParseError("Word is non alphabetical.") #Otherwise: else: #If the first two characters of the line are "</": if line[0:2] == "</": current_tag = tag_stack.pop() bit = "<" + line[2:] + ">" #If the rest of the line is non alphabetic raise an exception. if not line[2:].isalpha(): raise ParseError("Tag is non alphabetical.") #Otherwise if the end tag matches the current opening tag: elif current_tag != [] and current_tag[0] == bit: #End tag is added & then the whole tag line is added to #the proceeding tag line. current_tag.append(line + ">") new_tag = tag_stack.pop() new_tag.append(current_tag) tag_stack.push(new_tag) tag_checker.pop() #Otherwise if no open tag or end tag doesn't match open tag: #raise exception. elif current_tag == [] or current_tag[0] != bit: raise ParseError("Tag not balanced.") #Otherwise if the first character is "<": elif line[0] == "<": #If the tag is made of letters: if line[1:].isalpha(): #Open tag is added to tag_stack & tag_checker otherwise #raise exception. tag_stack.push([line + ">"]) tag_checker.push(line + ">") else: raise ParseError("Tag is non alphabetical.") #Otherwise if the line is non alphabetic & not a space: #raise exception. elif not line.isalpha() and not piece.isspace(): raise ParseError("Word is non alphabetical.") #Variable result is assigned the remaining tag line result = tag_stack.pop() #If there's still an open tag: raise exception. Otherwise return result. if not tag_checker.empty(): raise ParseError("Tags not balanced.") else: return result if __name__ == '__main__': # The second example from the assignment description doc = '<html>\n\ <head><title>Example\n</title></head>\n\ <body>quiet<CAPSLOCK> LOUD </CAPSLOCK> quiet</body>\n\ </html>' print parse(doc)