删除所有嵌套块,同时通过python单独保留非嵌套块

时间:2009-12-27 08:01:21

标签: python regex recursion nested brackets

来源:

[This] is some text with [some [blocks that are nested [in a [variety] of ways]]]

结论文字:

[This] is some text with

通过查看threads at stack overflow,我认为你不能为此做正则表达式。

有一种简单的方法可以做到这一点 - >或者必须到达pyparsing(或其他解析库)?

4 个答案:

答案 0 :(得分:5)

这是一种不需要任何依赖关系的简单方法:扫描文本并为你传递的大括号保留一个计数器。每次看到“[”时递增计数器;每次看到“]”时都会减少它。

  • 只要计数器为零或一,将您看到的文本放在输出字符串上。
  • 否则,您处于嵌套块中,因此请勿将文本放在输出字符串上。
  • 如果计数器没有在零结束,则字符串格式错误;你有不等数量的开合括号。 (如果它大于零,那么你有多少[ s;如果它小于零,那么你就会有那么多] s。)

答案 1 :(得分:4)

将OP的示例作为规范(必须删除包含更多嵌套块的任何块),那么......:

import itertools

x = '''[This] is some text with [some [blocks that are nested [in a [variety]
of ways]]] and some [which are not], and [any [with nesting] must go] away.'''

def nonest(txt):
  pieces = []
  d = 0
  level = []
  for c in txt:
    if c == '[': d += 1
    level.append(d)
    if c == ']': d -= 1
  for k, g in itertools.groupby(zip(txt, level), lambda x: x[1]>0):
    block = list(g)
    if max(d for c, d in block) > 1: continue
    pieces.append(''.join(c for c, d in block))
  print ''.join(pieces)

nonest(x)

这会发出

[This] is some text with  and some [which are not], and  away.

在正常时间假设下似乎是理想的结果。

我们的想法是在level中计算一个并行的计数列表“我们此时如何嵌套”(即到目前为止我们遇到了多少已打开且尚未关闭的括号);然后将带有level的文本的groupby的zip分段为具有零嵌套和嵌套的备用块> 0.对于每个块,然后计算此处的最大嵌套(对于具有零嵌套的块将保持为零 - 更一般地,它仅是整个块中嵌套级别的最大值),并且如果得到的嵌套是< = 1 ,保留相应的文本块。请注意,我们需要将组g放入列表block,因为我们要执行两次迭代过程(一次用于获取最大嵌套,一次用于将字符重新加入一个文本块) - 要在一次传递中执行它,我们需要在嵌套循环中保留一些辅助状态,在这种情况下这样做不太方便。

答案 2 :(得分:3)

编写解析器会更好,尤其是在使用像pyparsing这样的解析器生成器时。它将更易于维护和扩展。

实际上pyparsing已经为你实现了parser,你只需编写过滤解析器输出的函数。

答案 3 :(得分:3)

我编写了一个可以与expression.transformString()一起使用的解析器表达式,但是我在解析时很难区分嵌套和unnested []。最后,我不得不在transformString中打开循环并显式迭代scanString生成器。

为了解决是否应该根据原始问题包含[某些]的问题,我通过使用此字符串在末尾添加更多“unnested”文本来探讨这一点:

src = """[This] is some text with [some [blocks that are 
    nested [in a [variety] of ways]] in various places]"""

我的第一个解析器遵循原始问题的引导,拒绝任何包含任何嵌套的括号中的表达式。我的第二次传递采用任何括号表达式的顶级标记,并将它们放在括号中 - 我不太喜欢这个解决方案,因为我们失去了“某些”和“在不同的地方”不连续的信息。所以我接受了最后一次传递,并且必须对nestedExpr的默认行为稍作修改。请参阅以下代码:

from pyparsing import nestedExpr, ParseResults, CharsNotIn

# 1. scan the source string for nested [] exprs, and take only those that
# do not themselves contain [] exprs
out = []
last = 0
for tokens,start,end in nestedExpr("[","]").scanString(src):
    out.append(src[last:start])
    if not any(isinstance(tok,ParseResults) for tok in tokens[0]):
        out.append(src[start:end])
    last = end
out.append(src[last:])
print "".join(out)


# 2. scan the source string for nested [] exprs, and take only the toplevel 
# tokens from each
out = []
last = 0
for t,s,e in nestedExpr("[","]").scanString(src):
    out.append(src[last:s])
    topLevel = [tok for tok in t[0] if not isinstance(tok,ParseResults)]
    out.append('['+" ".join(topLevel)+']')
    last = e
out.append(src[last:])
print "".join(out)


# 3. scan the source string for nested [] exprs, and take only the toplevel 
# tokens from each, keeping each group separate
out = []
last = 0
for t,s,e in nestedExpr("[","]", CharsNotIn('[]')).scanString(src):
    out.append(src[last:s])
    for tok in t[0]:
        if isinstance(tok,ParseResults): continue
        out.append('['+tok.strip()+']')
    last = e
out.append(src[last:])
print "".join(out)

,并提供:

[This] is some text with 
[This] is some text with [some in various places]
[This] is some text with [some][in various places]

我希望其中一个接近OP的问题。但如果不出意外,我还要进一步探索nestedExpr的行为。