【问题标题】:How to construct a tree from string?如何从字符串构造一棵树?
【发布时间】:2020-12-08 10:10:36
【问题描述】:

输入字符串:'(SBARQ (WHADVP (WRB Where)) (VBZ is) (NP (DT the) (NN cow)))'

这是树的样子:

旨在构建一个TreeNode,标签为节点,其所有覆盖字符串为值。

class TreeNode:
   def __init__(self):
        self.childre=[]
        self.label=""
        self.text=""

这是树的预期外观:

SBARQ: "Where is the cow"
WHADVP: "Where"
WRB: "Where"
VBZ: "is"
NP: "the cow"
DT: "the"
NN: "cow"

【问题讨论】:

  • 你放在最后的示例值是text?
  • 您的问题有两个答案。有任何 cmet 或反馈吗?

标签: python tree nltk


【解决方案1】:

主要是识别孩子。我将尝试解释我的代码:

class TreeNode:
    def __init__(self, string):
        
        self.im_leaf = string[0] != '('
        self.children = []

        if not self.im_leaf:
            first_space_index = string.index(" ")
            self.label = string[1:first_space_index]
            
            string = string[first_space_index + 1 : -1] #rest of the tree
            for node in self.split(string):
                self.children.append(TreeNode(node))
        else:
            self.label = string

        self.text = self.calculate_text()

    def calculate_text(self):
        if self.im_leaf:
            return self.label + ' '
        
        text = ''
        for node in self.children:
            text += node.calculate_text()

        return text


    def split(self, string):
        
        splitted = []
        pair_parenthesis = 0 
        index = 0

        for i in range(len(string)):
            char = string[i]

            if char == '(':
                pair_parenthesis += 1
            elif char == ')':
                pair_parenthesis -= 1
                if pair_parenthesis == 0:

                    new_node = string[index:i+1]
                    if new_node[0] == ' ':
                        new_node = new_node[1:]
                    splitted.append(new_node)
                    index = i + 1

        if len(splitted) == 0:  
            splitted = [string]
        
        return splitted

首先,在__init__ 中,我知道给定的字符串是否描述了由第一个字符确定的叶子,如果它不是“开括号”('('),那么当前字符串描述的是叶子,例如"cow"Where;与 "(NP (DT the) (NN cow))" 等“非叶字符串”不同。

如果string 描述了一片叶子,那么label = string,否则label 是第一个括号(始终位于第一个位置)和第一个空格之间的子字符串。此外,在后一种情况下,需要识别不同的分支,这可以通过 split 方法完成。然后,递归识别children

split 方法通过计算开括号和闭括号来识别分支。请注意"(WHADVP (WRB Where)) (VBZ is) (NP (DT the) (NN cow))" 中的第一个分支是(WHADVP (WRB Where)),即代码中开括号的数量第一次等于闭括号的数量(这个差异是存储在pair_parenthesis 中的)。第二个和第三个分支也是如此。如果一个分支只有一个子分支,例如"(WRB Where)",则该方法将使用字符串"Where" 调用,在这种情况下,它会返回"[Where]"

最后,text 被分配给calculate_text 方法,它基本上通过树搜索叶子进行递归调用。如果节点是叶子,则将其标签添加到text

现在进行一些测试:

test_tree = TreeNode('(SBARQ (WHADVP (WRB Where)) (VBZ is) (NP (DT the) (NN cow)))')

print(test_tree.label)
#SBARQ

print(test_tree.text)
#Where is the cow 

print(test_tree.children[0].text) #text from the "WHADVP" node
#Where

如果有什么不清楚的地方请告诉我。

【讨论】:

    【解决方案2】:

    您可以使用递归同时创建树和聚合文本。

    我愿意:

    • 允许使用标签参数调用构造函数;
    • 将用于从字符串创建树的函数定义为类的静态方法;
    • 使用正则表达式对输入进行标记;
    • 添加一些assert 语句,当输入格式不符合预期时,这些语句将显示可读的异常消息;
    • 在您的类上定义 __iter__,以便您可以轻松地遍历树中存在的所有节点
    import re
    
    class TreeNode:
        def __init__(self, label=""):
            self.children = []
            self.label = label
            self.text = ""
    
        @staticmethod
        def create_from_string(text):
            tokens = re.finditer(r"[()]|[^\s()]+", text)
            match = next(tokens)
            token = match.group()
            assert token == "(", "Expected '(' at {}, but got '{}'".format(match.start(), token)
    
            def recur():
                node = None
                while True:
                    match = next(tokens)
                    i = match.start()
                    token = match.group()
                    if token == ")":
                        assert node, "Expected label at {}, but got ')'".format(i)
                        assert node.text, "Expected text at {}, but got ')'".format(i)
                        return node
                    if token == "(":
                        assert node, "Expected label at {}, but got '('".format(i)
                        child = recur()
                        node.children.append(child)
                        token = child.text
                    if node:
                        node.text = "{} {}".format(node.text, token).lstrip() 
                    else:
                        node = TreeNode(token)
    
            return recur()
    
        def __iter__(self):
            def nodes():
                yield self
                for child in self.children:
                    yield from child
            return nodes()
    

    以下是如何将上述内容用于您的具体示例:

    s = '(SBARQ (WHADVP (WRB Where)) (VBZ is) (NP (DT the) (NN cow)))'
    tree = TreeNode.create_from_string(s)
    for node in tree:
        print("{}: {}".format(node.label, node.text))
    

    后面的代码将输出:

    SBARQ: Where is the cow
    WHADVP: Where
    WRB: Where
    VBZ: is
    NP: the cow
    DT: the
    NN: cow
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      • 2021-08-06
      • 2018-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多