【问题标题】:Remove all nested blocks, whilst leaving non-nested blocks alone via python删除所有嵌套块,同时通过 python 单独保留非嵌套块
【发布时间】:2009-12-27 08:01:21
【问题描述】:

来源:

[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(或其他解析库)?

【问题讨论】:

  • 我认为您的示例有误。不应该是 [This] 是带有 [some] 的一些文本吗? “with”之后的部分内的文本没有嵌套。
  • +1 用于在您询问之前进行搜索。

标签: python regex recursion nested brackets


【解决方案1】:

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

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

【讨论】:

  • 但在他的示例中,[some 将使用您的方法放入输出字符串中。您必须保存出现在“级别 1”的文本,并且只有在此块中没有出现更高级别时才将其放入输出字符串中。
  • 我不确定该示例是否不正确,因为这似乎是一个错字。直到内部括号,该块才“嵌套”。但如果不是这种情况,您所要做的就是仅在遇到“]”时才写入输出(在这种情况下,如果计数器太深则丢弃,或者如果计数器正常则写入)或结束字符串。
【解决方案2】:

以 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的zip与groupby的文本分割成零嵌套和嵌套> 0的交替块。对于每个块,然后计算此处的最大嵌套(对于零嵌套的块将保持为零-更一般地说,它只是整个块中嵌套级别的最大值),如果生成的嵌套 g 放入列表 block 中,因为我们要执行两次迭代(一次获得最大嵌套,一次将字符重新加入文本块)——在我们需要在嵌套循环中保留一些辅助状态,这在这种情况下不太方便。

【讨论】:

  • 我需要一些时间来消化这个答案中的信息。但有一件事是肯定的,它非常有效。
【解决方案3】:

你最好写一个解析器,特别是如果你使用像pyparsing这样的解析器生成器。它将更易于维护和扩展。

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

【讨论】:

    【解决方案4】:

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

    为了解决是否应该根据原始问题包含 [some] 的问题,我通过在末尾添加更多“未嵌套”文本进行了探索,使用以下字符串:

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

    我的第一个解析器遵循原始问题的引导,并拒绝任何具有 any 嵌套的括号表达式。我的第二遍获取任何括号表达式的顶级标记,并将它们返回到括号中 - 我不太喜欢这个解决方案,因为我们丢失了“一些”和“在各个地方”不连续的信息。所以我最后一次通过,不得不对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 的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多