在嵌套括号中从python获取字符串

时间:2015-01-24 18:54:27

标签: python text-parsing

我有一个像

这样的字符串
  

(0(1(2(3(4(5))(6室))(7(8)(9(10极)(11好))))   (12但))(13(14(15)(16食品))(17(18)(19(20))(21   坏))))))(22。))

实际上是一棵树:

enter image description here

我想获得一个给定节点的字符串,即如果说节点0我应该收到“房间非常好,但食物很糟糕。”如果我说节点2我应该收到“房间非常好”但节点5“The”等等。

3 个答案:

答案 0 :(得分:2)

我首先构建一个明显的树(其中节点有子节点和可能的字符串有效负载)然后处理它以获得您想要的替代(使用包含子有效负载的字符串)。例如,草稿(无错误检查& c):

class Node(object):
    def __init__(self, n):
        self.n = n
        self.children = []
        self.text = []
        self.payload = self.wholestring = ''

def make_payload_tree(astring):
    root = Node(-1)
    parents = [root]
    sit = iter(astring)
    for c in sit:
        if c=='(':
            mkn = []
            for c in sit:
                if c==' ': break
                mkn.append(c)
            newnode = Node(int(''.join(mkn)))
            parents[-1].children.append(newnode)
            parents.append(newnode)
        elif c==')':
            oldnode = parents.pop()
            oldnode.payload = ''.join(oldnode.text)
        else:
            parents[-1].text.append(c)
  return root

您可以粗略地验证此有效负载树是否正确,例如:

def print_tree(r, ind=0):
    print ' '*ind, r.n, r.payload, r.wholestring
    for c in r.children:
        print_tree(c, ind + 2)

当然,此时wholestring仍为空字符串。

现在,第二遍可以构建wholestring属性:

def makewhole(node):
    for c in node.children:
        makewhole(c)
    s = node.payload + ' '.join(c.wholestring for c in node.children)
    node.wholestring = s.replace('  ', ' ')

并且print_tree应该验证您拥有所需的wholestring

现在有趣的部分是正确的错误诊断(如果输入字符串中存在任何“语法错误”,则此代码非常脆弱,并且您的示例隐含了其语法,从来没有明确表示),但这可能最好用一个合适的词法分析器和解析器方法,而不是像我在这里做的临时解析。

答案 1 :(得分:2)

您可以使用pyparsing解析字符串:

s='(0 (1 (2 (3 (4 (5 The) (6 room)) (7 (8 was) (9 (10 very) (11 good)))) (12 but)) (13 (14 (15 the) (16 food)) (17 (18 was) (19 (20 very) (21 bad))))) (22 .))'

from pyparsing import *
enclosed = Forward()
nestedParens = nestedExpr('(', ')', content=enclosed) 
enclosed << (Word(alphanums+'.') | ',' | nestedParens)

>>> enclosed.parseString(s).asList()  
[['0', ['1', ['2', ['3', ['4', ['5', 'The'], ['6', 'room']], ['7', ['8', 'was'], ['9', ['10', 'very'], ['11', 'good']]]], ['12', 'but']], ['13', ['14', ['15', 'the'], ['16', 'food']], ['17', ['18', 'was'], ['19', ['20', 'very'], ['21', 'bad']]]]], ['22', '.']]]

然后根据需要处理嵌套数据。

答案 2 :(得分:0)

第一个问题是,如何解析字符串。

每个node看似({number} {word | node node})number\d+word[\w,.]+。这种描述非常适合递归下降解析器。

第二个问题是,如何存储结果树,以便我可以轻松找到节点及其后代。

我建议按节点编号索引dict - 类似于

tree = {
    0: (1, 22),
    1: (2, 13),
    2: (3, 12),
    # ...
    20: "very",
    21: "bad",
    22: "."
}

这允许您直接跳转到任何节点,并从那里跟随树来重新创建句子片段。