2009-12-27 63 views
3

来源:删除所有嵌套块,而只留下非嵌套块通过Python

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

+0

我认为你的例子有误。它不应该[这]是一些文字与[一些]?紧跟在“with”之后的部分中的文本不是嵌套的。 – 2009-12-27 08:14:47

+0

+1之前你问。 – Kobi 2009-12-27 10:20:19

回答

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. 

其中normatime假设下,似乎是所期望的结果。

这个想法是在level中计算一个并行的计数列表“我们在这一点上是多么嵌套”(即,迄今为止我们遇到了多少已打开和尚未关闭的括号);然后将level的文本与文本groupby一起拆分为零嵌套和嵌套> 0的替代块。对于每个块,计算此处的最大嵌套(对于嵌套为零的块将保持为零) - 更一般地说,它是只是整个块中嵌套层次的最大值),如果产生的嵌套为< = 1,则保留相应的文本块。请注意,我们需要将组g放入列表block中,因为我们要执行两次迭代过程(一次获得最大嵌套,一次将字符重新加入到文本块中) - 在单次传递中需要在嵌套循环中保留一些辅助状态,这在这种情况下不太方便。

+0

我需要一些时间来消化这个答案中的信息。但有一点可以肯定,它的效果非常出色。 – torger 2009-12-28 01:44:07

5

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

  • 只要计数器为零或一个,将您看到的文本放到输出字符串中。
  • 否则,您处于嵌套块中,因此不要将文本放到输出字符串中。
  • 如果计数器未完成为零,则该字符串格式不正确;你有不同数量的开合支撑。 (如果是大于零,你有很多多余的[秒;如果是小于零,你有很多多余的]秒)
+0

+1这正是我要说的。 – 2009-12-27 08:19:56

+4

但在他的例子中,''有些'会被放在输出字符串中使用你的方法。如果在此块中没有更高级别,则必须保存出现在“级别1”的文本,并仅将其放入输出字符串中。 – 2009-12-27 08:50:27

+0

我不确定这个例子是不正确的,因为这看起来像一个错字。该块不是“嵌套”,直到内部支架。但如果情况并非如此,那么你只需要在遇到“]”时写入输出(在这种情况下,如果计数器太深,或者如果计数器没有问题,则丢弃)或者结束串。 – 2009-12-27 09:29:17

3

你会好起来的编写解析器,特别是如果你使用的解析器发电机如pyparsing。它将更易于维护和扩展。

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

3

我在写一个可以与expression.transformString()一起使用的解析器表达式的过程中花费了一些时间,但是我在解析时很难区分嵌套和非嵌入[]。最后,我不得不在transformString中打开循环,并显式地遍历scanString生成器。

为了解决是否[某些]应在原有基础上的问题被列入与否,我探讨过这个由末,加入更多的“嵌套的”文本使用该字符串的问题:

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