【问题标题】:How to parse a tree from a string in Python?如何从 Python 中的字符串解析树?
【发布时间】:2018-03-25 17:37:31
【问题描述】:

我的所有大学笔记格式如下:

CourseName: {
    Part 1: {
        I.I - Intro: {
            Topic1: {
                descr1;
                descr2: {
                    2.a;
                    2.b;
                    2.c.
                };
                descr3.
            };
            Topic2: {
                descr: {
                    example.
                }.
            }.
        };
        I.II - NextChapter: {
            Topic3: {
                whatever.
            }.
        }.
    };
    Part 2: {
        II.I - FinalChapter: {
            content.
        }.
    }.
}

我想将它们构造成一个树数据结构,在过去的几个小时里,我已经尝试过递归和迭代地这样做,做了很多研究在线,但我的尝试都没有奏效。

我已经实现了一个 Node 类(带有 self.__value 和一个列表 self.__children 以及您期望从中获得的所有有用方法)以及一个 Tree 类(使用self.__nodes 作为字典 和其他实用方法),因此请随意在答案中以任何您喜欢的形式使用add_node 或add_child 等方法。

我正在努力的是了解如何构造函数def parseTree(s, l) - 理想情况下,输入字符串s(我的笔记)和列表l 建立分隔符即[":{", ";", "}."] 或@ 987654331@ 或类似的 - 并返回一个树对象,每个节点的值都是 :{ 之前的文本和文本中由 ; 分隔的子项列表(如果有)。

有什么建议吗?

【问题讨论】:

  • 显示你的代码!
  • 您应该首先将它们重新格式化为可解析的形式(JSON、yaml 等)。
  • chepner 和 Daniel Roseman 是对的——使用现有的解析器总是更容易。但是如果你确实想自己做这件事,我认为你可能缺少的是,你已经完成了设计自定义递归下降解析器的 75%,但还没有想到递归地实现它。这可能会帮助您搜索。但是,另一方面,你的语言更简单,你可以编写一个简单的语法来提供给解析器生成器或解析器框架,而不是编写代码,所以你可能想要搜索它。
  • @ekhumoro 我知道我必须展示它,但我有点做不到,因为它是一个没有运行的混乱,是反复试验的结果,更多的是关于如何解决问题的一般想法比实际代码
  • @abarnert 非常感谢,这正是我想要做和寻找的。一个全新的世界刚刚向我敞开!我也愿意重新格式化我的“语法”,使其尽可能简单和可解析以使其工作。但是 75% 的路还很长……我仍然对如何取得进展一无所知。

标签: python parsing tree text-parsing parse-tree


【解决方案1】:

这实际上是几乎在语法上有效的 YAML。一个简单的替换将使其有效:

data = data.replace(';', ',').replace('.', '')
parsed = yaml.load(data)

【讨论】:

  • 你可能想要一些更具体的替换,至少只是 ; 和 . 结束一行。
【解决方案2】:

假设您的数据存储在文件中,您可以构建一个简单的类来将结构解析为字典。您可以通过为找到的每个键创建一个新的Notes 对象来递归遍历数据:

file_data = filter(None, [i.strip('\n') for i in open('filename.txt')])
import re
class Notes:
   def __init__(self, token_data):
     self.token_data = token_data
     self.current_dict = {}
     self.current_vals = []
     self.parse()
   def parse(self):
     while True:
       start = next(self.token_data, None)
       if not start or "}" in start:
         break
       if start.endswith('{'):
          note = Notes(self.token_data)
          final_result = filter(lambda x:x, note.current_vals + [note.current_dict]) if note.current_vals else note.current_dict
          self.current_dict[re.findall('[\w\s\-\.]+', re.sub('^\s+', '', start))[0]] = final_result[0] if isinstance(final_result, list) and len(final_result) == 1 else final_result
          self.token_data = note.token_data
       else:
          self.current_vals.append(re.sub('^\s+', '', start))


course_notes = Notes(iter(file_data)).current_dict

输出:

{'CourseName': 
    {'Part 1': 
      {'I.I - Intro': 
         {'Topic1': ['descr1;',
                    'descr3.',
             {'descr2': ['2.a;',
                         '2.b;',
                          '2.c.']
                }
               ],
         'Topic2': {'descr': 'example.'}
                 },
                  'I.II - NextChapter': 
               {'Topic3': 'whatever.'}
             },
       'Part 2':{'II.I - FinalChapter': 'content.'}
     } 
   }

【讨论】:

  • 这很酷且有效,是的,数据确实存储在文本文件中。我只希望我能看懂你写的一半代码,哈哈
  • @FlynnRhodes 很高兴为您提供帮助!我在帖子中添加了更多解释,但是,所有代码所做的只是为每次出现的数据键创建一个新类。文件数据存储为迭代器,这样可以更容易地确定数据源何时耗尽。
猜你喜欢
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2021-10-29
  • 2016-06-29
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
相关资源
最近更新 更多