资源:
[This] is some text with [some [blocks that are nested [in a [variety] of ways]]]
结果文本:
[This] is some text with
我不认为你可以通过查看stack overflow 的线程来为此做一个正则表达式。
有没有一种简单的方法可以做到这一点-> 或者必须使用 pyparsing(或其他解析库)?
这是一种不需要任何依赖项的简单方法:扫描文本并为您传递的大括号保留一个计数器。每次看到“[”时增加计数器;每次看到“]”时减少它。
[
s;如果它小于零,你就有那么多多余]
的 s。)以 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
因为我们想要执行两次迭代(一次获得最大嵌套,一次将字符重新加入文本块)——要在一次遍历中完成,我们需要在嵌套循环中保留一些辅助状态,在这种情况下不太方便。
在编写可以与 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 的行为。