Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import copy
- import sys
- class Document(object):
- def __init__(self):
- self.children = []
- def add_child(self, section):
- self.children.append(section)
- def to_text(self, output_stream):
- for section in self.children:
- section.to_text(output_stream)
- class BaseSection(object):
- def __init__(self):
- self.children = []
- self.text_lines = []
- def add_line(self, line):
- self.text_lines.append(line)
- def add_child(self, section):
- self.children.append(section)
- def to_text(self, output_stream):
- section_prefix = self.get_section_prefix()
- output_stream.write(section_prefix)
- if not self.text_lines:
- output_stream.write("\n")
- return
- first_line = self.text_lines[0]
- output_stream.write(first_line)
- output_stream.write("\n")
- for line in self.text_lines[1:]:
- prefix = self.get_additional_line_prefix()
- output_stream.write(prefix)
- output_stream.write(line)
- output_stream.write("\n")
- for child in self.children:
- child.to_text(output_stream)
- def get_section_prefix(self):
- raise NotImplementedError
- def get_additional_line_prefix(self):
- raise NotImplementedError
- class NumberedSection(BaseSection):
- def __init__(self, section_numbers_list):
- super(NumberedSection, self).__init__()
- if type(section_numbers_list) != list:
- raise ValueError("section_numbers_list must be a list")
- self.section_numbers_list = section_numbers_list
- def get_section_prefix(self):
- prefix = ""
- for number in self.section_numbers_list:
- prefix += str(number)
- prefix += "."
- prefix = prefix[:-1]
- prefix += " "
- return prefix
- def get_additional_line_prefix(self):
- return " "
- class SubSection(BaseSection):
- def __init__(self, indent_level=0):
- super(SubSection, self).__init__()
- if type(indent_level) != int:
- raise ValueError("indent_level must be an integer")
- self.indent_level = indent_level
- def get_section_prefix(self):
- prefix = ""
- for indent_num in range(0, self.indent_level):
- prefix += " "
- if prefix:
- prefix += " "
- if self.children:
- prefix += "+"
- else:
- prefix += "-"
- prefix += " "
- return prefix
- def get_additional_line_prefix(self):
- prefix = ""
- for indent_num in range(0, self.indent_level+1):
- prefix += " "
- return prefix
- class Parser(object):
- _special_chars = ["*", "."]
- def __init__(self, encoding="utf-8"):
- self.document = Document()
- self.encoding = encoding
- self.text_buffer = ""
- self.section_stack = []
- self.numbered_section_position = []
- self.lines_parsed = 0
- def feed(self, data):
- if type(data) in [bytes, bytearray]:
- text = data.decode(self.encoding)
- elif type(data) in [str, unicode]:
- text = data
- else:
- raise ValueError("data must be bytes, bytearray, str, or unicode")
- self.text_buffer += text
- def flush_buffer(self):
- lines = self.text_buffer.split("\n")
- for line in lines[:-1]:
- self.parse_line(line)
- self.text_buffer = lines[-1]
- def parse_line(self, line):
- if not line:
- return
- num_special_chars = 0
- if line[0] in self._special_chars:
- special_char = line[0]
- else:
- self.section_stack[-1].add_line(line)
- return
- for char in line:
- if char == special_char:
- num_special_chars += 1
- else:
- break
- text_only = line[num_special_chars:]
- if text_only[0] != " ":
- raise ValueError("Must include a space after section directive. Line " + str(self.lines_parsed + 1))
- text_only = text_only[1:]
- if special_char == "*":
- self.section_stack = []
- add_subsection_numbers = num_special_chars - len(self.numbered_section_position)
- if add_subsection_numbers > 0:
- for subsection_number in range(0, add_subsection_numbers):
- self.numbered_section_position.append(1)
- else:
- self.numbered_section_position[num_special_chars - 1] += 1
- self.numbered_section_position = self.numbered_section_position[:num_special_chars]
- section = NumberedSection(copy.copy(self.numbered_section_position))
- section.add_line(text_only)
- self.document.add_child(section)
- self.section_stack.append(section)
- elif special_char == ".":
- self.section_stack = self.section_stack[:num_special_chars]
- section = SubSection(indent_level=len(self.section_stack))
- section.add_line(text_only)
- self.section_stack[-1].add_child(section)
- self.section_stack.append(section)
- def close(self):
- if self.text_buffer and self.text_buffer[-1] != "\n":
- self.text_buffer += "\n"
- self.flush_buffer()
- if __name__ == "__main__":
- parser = Parser()
- for line in sys.stdin.readlines():
- parser.feed(line)
- parser.close()
- parser.document.to_text(sys.stdout)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement