Advertisement
Guest User

Untitled

a guest
May 22nd, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.50 KB | None | 0 0
  1. import copy
  2. import sys
  3.  
  4. class Document(object):
  5. def __init__(self):
  6. self.children = []
  7.  
  8. def add_child(self, section):
  9. self.children.append(section)
  10.  
  11. def to_text(self, output_stream):
  12. for section in self.children:
  13. section.to_text(output_stream)
  14.  
  15. class BaseSection(object):
  16. def __init__(self):
  17. self.children = []
  18. self.text_lines = []
  19.  
  20. def add_line(self, line):
  21. self.text_lines.append(line)
  22.  
  23. def add_child(self, section):
  24. self.children.append(section)
  25.  
  26. def to_text(self, output_stream):
  27. section_prefix = self.get_section_prefix()
  28. output_stream.write(section_prefix)
  29. if not self.text_lines:
  30. output_stream.write("\n")
  31. return
  32. first_line = self.text_lines[0]
  33. output_stream.write(first_line)
  34. output_stream.write("\n")
  35. for line in self.text_lines[1:]:
  36. prefix = self.get_additional_line_prefix()
  37. output_stream.write(prefix)
  38. output_stream.write(line)
  39. output_stream.write("\n")
  40. for child in self.children:
  41. child.to_text(output_stream)
  42.  
  43. def get_section_prefix(self):
  44. raise NotImplementedError
  45.  
  46. def get_additional_line_prefix(self):
  47. raise NotImplementedError
  48.  
  49. class NumberedSection(BaseSection):
  50. def __init__(self, section_numbers_list):
  51. super(NumberedSection, self).__init__()
  52. if type(section_numbers_list) != list:
  53. raise ValueError("section_numbers_list must be a list")
  54. self.section_numbers_list = section_numbers_list
  55.  
  56. def get_section_prefix(self):
  57. prefix = ""
  58. for number in self.section_numbers_list:
  59. prefix += str(number)
  60. prefix += "."
  61. prefix = prefix[:-1]
  62. prefix += " "
  63. return prefix
  64.  
  65. def get_additional_line_prefix(self):
  66. return " "
  67.  
  68. class SubSection(BaseSection):
  69. def __init__(self, indent_level=0):
  70. super(SubSection, self).__init__()
  71. if type(indent_level) != int:
  72. raise ValueError("indent_level must be an integer")
  73. self.indent_level = indent_level
  74.  
  75. def get_section_prefix(self):
  76. prefix = ""
  77. for indent_num in range(0, self.indent_level):
  78. prefix += " "
  79. if prefix:
  80. prefix += " "
  81. if self.children:
  82. prefix += "+"
  83. else:
  84. prefix += "-"
  85. prefix += " "
  86. return prefix
  87.  
  88. def get_additional_line_prefix(self):
  89. prefix = ""
  90. for indent_num in range(0, self.indent_level+1):
  91. prefix += " "
  92. return prefix
  93.  
  94. class Parser(object):
  95. _special_chars = ["*", "."]
  96.  
  97. def __init__(self, encoding="utf-8"):
  98. self.document = Document()
  99. self.encoding = encoding
  100. self.text_buffer = ""
  101. self.section_stack = []
  102. self.numbered_section_position = []
  103. self.lines_parsed = 0
  104.  
  105. def feed(self, data):
  106. if type(data) in [bytes, bytearray]:
  107. text = data.decode(self.encoding)
  108. elif type(data) in [str, unicode]:
  109. text = data
  110. else:
  111. raise ValueError("data must be bytes, bytearray, str, or unicode")
  112. self.text_buffer += text
  113.  
  114. def flush_buffer(self):
  115. lines = self.text_buffer.split("\n")
  116. for line in lines[:-1]:
  117. self.parse_line(line)
  118. self.text_buffer = lines[-1]
  119.  
  120. def parse_line(self, line):
  121. if not line:
  122. return
  123. num_special_chars = 0
  124. if line[0] in self._special_chars:
  125. special_char = line[0]
  126. else:
  127. self.section_stack[-1].add_line(line)
  128. return
  129.  
  130. for char in line:
  131. if char == special_char:
  132. num_special_chars += 1
  133. else:
  134. break
  135. text_only = line[num_special_chars:]
  136. if text_only[0] != " ":
  137. raise ValueError("Must include a space after section directive. Line " + str(self.lines_parsed + 1))
  138. text_only = text_only[1:]
  139. if special_char == "*":
  140. self.section_stack = []
  141. add_subsection_numbers = num_special_chars - len(self.numbered_section_position)
  142. if add_subsection_numbers > 0:
  143. for subsection_number in range(0, add_subsection_numbers):
  144. self.numbered_section_position.append(1)
  145. else:
  146. self.numbered_section_position[num_special_chars - 1] += 1
  147. self.numbered_section_position = self.numbered_section_position[:num_special_chars]
  148. section = NumberedSection(copy.copy(self.numbered_section_position))
  149. section.add_line(text_only)
  150. self.document.add_child(section)
  151. self.section_stack.append(section)
  152. elif special_char == ".":
  153. self.section_stack = self.section_stack[:num_special_chars]
  154. section = SubSection(indent_level=len(self.section_stack))
  155. section.add_line(text_only)
  156. self.section_stack[-1].add_child(section)
  157. self.section_stack.append(section)
  158.  
  159. def close(self):
  160. if self.text_buffer and self.text_buffer[-1] != "\n":
  161. self.text_buffer += "\n"
  162. self.flush_buffer()
  163.  
  164. if __name__ == "__main__":
  165. parser = Parser()
  166. for line in sys.stdin.readlines():
  167. parser.feed(line)
  168. parser.close()
  169. parser.document.to_text(sys.stdout)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement