【问题标题】:Removing data between double squiggly brackets with nested sub brackets in python在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 不,它必须在 {{ }} 而不仅仅是 { }

标签: python regex parsing


【解决方案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。无法测试这个,你需要尝试:)

      【讨论】:

        猜你喜欢
        • 2019-08-11
        • 2012-12-04
        • 2019-02-07
        • 2022-10-24
        • 2020-02-14
        • 1970-01-01
        • 1970-01-01
        • 2022-10-19
        相关资源
        最近更新 更多