在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中使用嵌套子括号删除双波浪括号之间的数据的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 之 子查询与嵌套查询

Python删除方括号和它们之间的无关信息

oracle的查询嵌套两层括号关联不上表

1.shell学习之常用语句

使用refs reactJS WithStyles调用嵌套子方法[重复]

Mongodb $pull 执行从嵌套子数组中删除 ObjectId("... id") 。