Rig*_*sby 5 python markup markdown parsing lexer
请参阅Edit-1中的更新输入和输出数据.
我想要完成的是转向
+ 1 + 1.1 + 1.1.1 - 1.1.1.1 - 1.1.1.2 + 1.2 - 1.2.1 - 1.2.2 - 1.3 + 2 - 3
进入python等数据结构
[{'1': [{'1.1': {'1.1.1': ['1.1.1.1', '1.1.1.2']}, '1.2': ['1.2.1', '1.2.2']}, '1.3'], '2': {}}, ['3',]]
我看过许多不同的wiki标记语言,markdown,重构文本等等,但是它们对我理解它是如何工作非常复杂,因为它们必须覆盖大量标签和语法(我只需要"列表")大部分的部分但当然转换为python而不是html.)
我还看了一下tokenizer,词法分析器和解析器,但是它们比我需要的要复杂得多,我能理解.
我不知道从哪里开始,并希望对此主题有任何帮助.谢谢
编辑-1:是的,行开头的字符很重要,从之前的必需输出开始,现在可以看出,*表示带有子节点的根节点,+有子节点,-没有子节点(根或其他) )并且只是与该节点有关的额外信息.这*并不重要,可以与+互换(我可以通过其他方式获得root状态.)
因此,新要求仅*用于表示有或没有孩子的节点,并且-不能有孩子.我也改变了它所以关键不是之后的文本,这*无疑会改变后来的实际标题.
例如
* 1 * 1.1 * 1.2 - Note for 1.2 * 2 * 3 - Note for root
会给
[{'title': '1', 'children': [{'title': '1.1', 'children': []}, {'title': '1.2', 'children': []}]}, {'title': '2', 'children': [], 'notes': ['Note for 1.2', ]}, {'title': '3', 'children': []}, 'Note for root']
或者如果你有另一个想法在python中表示大纲,那么就把它推进去.
编辑:感谢我编辑我的代码的规范中的澄清和更改,仍然使用显式Node类作为清晰的中间步骤 - 逻辑是将行列表转换为节点列表,然后转动该列表将节点放入树中(通过适当地使用它们的缩进属性),然后以可读的形式打印该树(这只是一个"调试 - 帮助"步骤,以检查树是否构造良好,当然可以注释掉脚本的最终版本 - 当然,它将从文件中获取行而不是将它们硬编码以进行调试! - ),最后构建所需的Python结构并打印它.这是代码,正如我们之后所看到的,结果几乎与OP指定的一个例外 - 但是,代码首先:
import sys
class Node(object):
  def __init__(self, title, indent):
    self.title = title
    self.indent = indent
    self.children = []
    self.notes = []
    self.parent = None
  def __repr__(self):
    return 'Node(%s, %s, %r, %s)' % (
        self.indent, self.parent, self.title, self.notes)
  def aspython(self):
    result = dict(title=self.title, children=topython(self.children))
    if self.notes:
      result['notes'] = self.notes
    return result
def print_tree(node):
  print ' ' * node.indent, node.title
  for subnode in node.children:
    print_tree(subnode)
  for note in node.notes:
    print ' ' * node.indent, 'Note:', note
def topython(nodelist):
  return [node.aspython() for node in nodelist]
def lines_to_tree(lines):
  nodes = []
  for line in lines:
    indent = len(line) - len(line.lstrip())
    marker, body = line.strip().split(None, 1)
    if marker == '*':
      nodes.append(Node(body, indent))
    elif marker == '-':
      nodes[-1].notes.append(body)
    else:
      print>>sys.stderr, "Invalid marker %r" % marker
  tree = Node('', -1)
  curr = tree
  for node in nodes:
    while node.indent <= curr.indent:
      curr = curr.parent
    node.parent = curr
    curr.children.append(node)
    curr = node
  return tree
data = """\
* 1
 * 1.1
 * 1.2
  - Note for 1.2
* 2
* 3
- Note for root
""".splitlines()
def main():
  tree = lines_to_tree(data)
  print_tree(tree)
  print
  alist = topython(tree.children)
  print alist
if __name__ == '__main__':
  main()
运行时,会发出:
 1
  1.1
  1.2
  Note: 1.2
 2
 3
 Note: 3
[{'children': [{'children': [], 'title': '1.1'}, {'notes': ['Note for 1.2'], 'children': [], 'title': '1.2'}], 'title': '1'}, {'children': [], 'title': '2'}, {'notes': ['Note for root'], 'children': [], 'title': '3'}]
除了键的排序(这当然是无关紧要的并且在dict中无法保证)之外,这几乎是按照要求进行的 - 除了这里所有注释都显示为带有键的dict条目notes和值为字符串列表的值(但如果列表为空,则省略注释条目,大致与问题中的示例相同).
在当前版本的问题中,如何表示注释略显不清楚; 一个注释显示为独立字符串,其他注释显示为值为字符串的条目(而不是我正在使用的字符串列表).目前尚不清楚是什么意味着该音符必须在一个案例中作为独立字符串出现,在所有其他案例中作为dict条目出现,因此我使用的这个方案更加规则; 如果一个音符(如果有的话)是单个字符串而不是一个列表,那么这是否意味着如果一个节点出现多个音符则会出错?在后一方面,我使用的这个方案更通用(让一个节点从0开始有任意数量的音符,而不是在问题中明显暗示的0或1).
写了这么多代码(预编辑的答案大约有一段时间,并帮助澄清和更改规格)以提供(我希望)99%的理想解决方案,我希望这能满足原始海报,因为最后的几个调整到使它们相互匹配的代码和/或规格对他来说应该很容易!