3

资源:

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

结果文本:

[This] is some text with

我不认为你可以通过查看stack overflow 的线程来为此做一个正则表达式。

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

4

4 回答 4

5

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

  • 只要计数器为零或一,就将您看到的文本放在输出字符串上。
  • 否则,您处于嵌套块中,因此不要将文本放在输出字符串中。
  • 如果计数器未在零处结束,则字符串格式错误;您的左大括号和右大括号的数量不相等。(如果它大于零,你就有那么多的多余[s;如果它小于零,你就有那么多多余]的 s。)
于 2009-12-27T08:07:57.037 回答
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然后将带有文本的 zip 分割groupby成具有零嵌套和嵌套 > 0 的交替块。对于每个块,然后计算此处的最大嵌套(对于具有零嵌套的块将保持为零 - 更一般地说,它只是整个块的最大嵌套级别),并且如果生成的嵌套 <= 1,则保留相应的文本块。注意我们需要把组g变成一个列表block因为我们想要执行两次迭代(一次获得最大嵌套,一次将字符重新加入文本块)——要在一次遍历中完成,我们需要在嵌套循环中保留一些辅助状态,在这种情况下不太方便。

于 2009-12-27T16:02:37.157 回答
3

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

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

于 2009-12-27T08:08:14.073 回答
3

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

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

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 的行为。

于 2009-12-27T11:00:02.103 回答