在python中使用嵌套子括号删除双波浪括号之间的数据
Posted
技术标签:
【中文标题】在python中使用嵌套子括号删除双波浪括号之间的数据【英文标题】:Removing data between double squiggly brackets with nested sub brackets in python 【发布时间】:2016-06-07 13:13:48 【问题描述】:我在处理这个问题时遇到了一些困难。我需要删除波浪括号中包含的所有数据。
像这样:
Hello world of the crazy need be sea there.
变成:
Hello there.
这是我的第一次尝试(我知道这很糟糕):
while 1:
firstStartBracket = text.find('')
if (firstStartBracket == -1):
break;
firstEndBracket = text.find('')
if (firstEndBracket == -1):
break;
secondStartBracket = text.find('',firstStartBracket+2);
lastEndBracket = firstEndBracket;
if (secondStartBracket == -1 or secondStartBracket > firstEndBracket):
text = text[:firstStartBracket] + text[lastEndBracket+2:];
continue;
innerBrackets = 2;
position = secondStartBracket;
while innerBrackets:
print innerBrackets;
#everytime we find a next start bracket before the ending add 1 to inner brackets else remove 1
nextEndBracket = text.find('',position+2);
nextStartBracket = text.find('',position+2);
if (nextStartBracket != -1 and nextStartBracket < nextEndBracket):
innerBrackets += 1;
position = nextStartBracket;
# print text[position-2:position+4];
else:
innerBrackets -= 1;
position = nextEndBracket;
# print text[position-2:position+4];
# print nextStartBracket
# print lastEndBracket
lastEndBracket = nextEndBracket;
print 'pos',position;
text = text[:firstStartBracket] + text[lastEndBracket+2:];
它似乎可以工作,但很快就会耗尽内存。有没有更好的方法来做到这一点(希望使用正则表达式)?
编辑:我不清楚,所以我再举一个例子。我需要允许多个***括号。
像这样:
Hello world of the crazy need be sea there my friend.
变成:
Hello there friend.
【问题讨论】:
所以基本上你想删除 中的所有内容,对吧? 但是,如果您不想使用regex
使用堆栈来计算开括号和右括号的数量,它比这里的示例代码更容易。
@GLHF 不,它必须在 而不仅仅是
【参考方案1】:
这是一个基于正则表达式/生成器的解决方案,适用于任意数量的大括号。这个问题不需要实际的堆栈,因为只涉及一种类型(嗯,对)的令牌。 level
扮演了堆栈在更复杂的解析器中扮演的角色。
import re
def _parts_outside_braces(text):
level = 0
for part in re.split(r'(\\|\\)', text):
if part == '':
level += 1
elif part == '':
level = level - 1 if level else 0
elif level == 0:
yield part
x = 'Hello world of the crazy need be sea there. second set of braces '
print(''.join(_parts_outside_braces(x)))
更一般的观点...正则表达式中的捕获组是使大括号出现在re.split
的输出中的原因,否则您只会得到介于两者之间的东西。对不匹配的大括号也有一些支持。对于严格的解析器,应该引发异常,就像在级别 > 0 的字符串末尾运行一样。对于松散的 Web 浏览器样式的解析器,也许您希望将这些 显示为输出......
【讨论】:
这实际上是迄今为止最快的解决方案。 ~ 15 µs【参考方案2】:您可以在此处使用pyparsing
module。基于this answer的解决方案:
from pyparsing import nestedExpr
s = "Hello world of the crazy need be sea there my friend."
expr = nestedExpr('', '')
result = expr.parseString("" + s + "").asList()[0]
print(" ".join(item for item in result if not isinstance(item, list)))
打印:
Hello there friend.
仅当只有一对***大括号时,以下方法才有效。
如果你想用大括号本身删除双花括号内的所有内容:
>>> import re
>>>
>>> s = "Hello world of the crazy need be sea there."
>>> re.sub(r"\\.*\\ ", "", s)
'Hello there.'
【讨论】:
仅当您假设***大括号不能超过一对时才有效。 @alecxe 很抱歉,我最初的问题并不清楚。while '' in s and '' in s
会处理@JasonS 的问题,尽管它会被''
搞砸...
@thewormsterror 确定,没问题,已更新为替代选项。【参考方案3】:
试试下面的代码:
import re
s = 'Hello world of the crazy need be sea there'
m = re.search('(.*?) .*(.*)',s)
result = m.group(1) + m.group(2)
print(result)
【讨论】:
仅当您假设***大括号不能超过一对时才有效。【参考方案4】:问题是你必须处理嵌套结构,这意味着正则表达式可能不够用。然而,一个具有深度记忆的简单解析器可能会来拯救 - 它写起来非常简单,只需存储 将深度级别转换为变量。
我只是在这里发布了一种更 Pythonic 的方式来编写解决方案,这可能对您来说是一个很好的参考。
import re
def rem_bra(inp):
i = 0
lvl = 0
chars = []
while i < len(inp):
if inp[i:i+2] == '':
lvl += 1
i += 1
elif inp[i:i+2] == '':
lvl -= 1
i += 1
else:
if lvl < 1:
chars.append(inp[i])
i += 1
result = ''.join(chars)
# If you need no more contigious spaces, add this line:
result = re.sub(r'\s\s+', r' ', result)
return result
inp = "Hello world of the crazy need be sea there."
print(rem_bra(inp))
>>> Hello there.
【讨论】:
【参考方案5】:为了更好的衡量标准,还有另一种解决方案。它首先找到并替换最左边的最里面的大括号,然后向外,向右工作。处理多个***大括号。
import re
def remove_braces(s):
pattern = r'\\(?:[^]|\[^])*?\\'
while re.search(pattern, s):
s = re.sub(pattern, '', s)
return s
不是最有效的,但很短。
>>> remove_braces('Hello world of the crazy need be sea there my friend.')
'Hello there friend.'
【讨论】:
你在开玩笑吗?你的效率很高。一个循环大约需要 90 ns,而大多数其他解决方案需要 10 - 25 微秒。 @Moritz 我猜是这样 :) 它确实多次搜索/匹配字符串,而 Jason S 的解决方案例如只执行一次。但我喜欢它简短。 编译你的函数需要 90ns @Moritz 你知道在所有答案中最快的解决方案是什么吗? 杰森的回答是。约 15 µs。我的大约是 25 µs。可能是因为我必须将可迭代对象转换为列表【参考方案6】:这个问题很有趣。这是我的尝试:
import re
def find_str(string):
flag = 0
for index,item in enumerate(string):
if item == '':
flag += 1
if item == '':
flag -= 1
if flag == 0:
yield index
s = 'Hello world of the crazy need be sea there my friend.'
index = list(find_str(s))
l = [s[i] for i in index]
s = ' '.join(l)
re.sub('\s+','',s)
'H e l l o t h e r e f r i e n d .'
【讨论】:
【参考方案7】:Python regex package 可以使用recursive regex。
(?>[^]+|(?0))* ?
或其他变体(需要更多步骤)。
(?>[^]*(?R)?)* ?
在(?0)
或(?R)
处粘贴模式。与regex.sub
一起使用
>>> import regex
>>> str = 'Hello world of the crazy need be sea there.'
>>> regex.sub(r'(?V1)(?>[^]+|(?0))* ?', '', str)
(?V1)
版本 1 的行为类似于 Perl。无法测试这个,你需要尝试:)
【讨论】:
以上是关于在python中使用嵌套子括号删除双波浪括号之间的数据的主要内容,如果未能解决你的问题,请参考以下文章