如何删除字符串中外括号之间的所有文本?

Posted

技术标签:

【中文标题】如何删除字符串中外括号之间的所有文本?【英文标题】:How to remove all text between the outer parentheses in a string? 【发布时间】:2016-09-28 10:38:30 【问题描述】:

当我有这样的字符串时:

s1 = 'stuff(remove_me)'

我可以轻松删除使用中的括号和文本

# returns 'stuff'
res1 = re.sub(r'\([^)]*\)', '', s1)

正如here 解释的那样。

但我有时会遇到这样的嵌套表达式:

s2 = 'stuff(remove(me))'

当我从上面运行命令时,我最终得到了

'stuff)'

我也试过了:

re.sub('\(.*?\)', '', s2)

这给了我相同的输出。

如何删除外括号内的所有内容 - 包括括号本身 - 以便最终得到 'stuff'(应该适用于任意复杂的表达式)?

【问题讨论】:

检查Remove text between () and [] in python @WiktorStribiżew:谢谢!但那是关于不嵌套的表达式。而且我很确定存在不需要大量 if-else 子句和 for 循环的东西。 这个answer 包含您需要的正则表达式,但您需要一个 PyPi 正则表达式模块。 【参考方案1】:

注意\(.*\) 匹配左起第一个 (,然后匹配任何 0+ 个字符(如果未启用 DOTALL 修饰符,则换行除外)直到 最后 ),并且不考虑正确嵌套的括号。

要在 Python 中使用正则表达式正确删除嵌套括号,您可以使用简单的 \([^()]*\)(匹配 (,然后是除 () 之外的 0+ 个字符然后在 while 块中使用)) re.subn:

def remove_text_between_parens(text):
    n = 1  # run at least once
    while n:
        text, n = re.subn(r'\([^()]*\)', '', text)  # remove non-nested/flat balanced parts
    return text

基本上:删除内部没有()(...),直到找不到匹配项。用法:

print(remove_text_between_parens('stuff (inside (nested) brackets) (and (some(are)) here) here'))
# => stuff   here

也可以使用非正则表达式:

def removeNestedParentheses(s):
    ret = ''
    skip = 0
    for i in s:
        if i == '(':
            skip += 1
        elif i == ')'and skip > 0:
            skip -= 1
        elif skip == 0:
            ret += i
    return ret

x = removeNestedParentheses('stuff (inside (nested) brackets) (and (some(are)) here) here')
print(x)              
# => 'stuff   here'

见another Python demo

【讨论】:

万一需要使用re 方法来删​​除嵌套的方括号,请使用r'\[[^][]*]' 模式。对于花括号,请使用 r'[^]*'【参考方案2】:

如前所述,您需要recursive regex 来匹配任意级别的嵌套,但如果您知道最多只能有一层嵌套,请尝试使用此模式:

\((?:[^)(]|\([^)(]*\))*\)
[^)(] 匹配一个不是括号的字符 (negated class)。 |\([^)(]*\) 或匹配另一个 ( ) 对,其中包含任意数量的 non )((?:...)* 这一切都在( )

Here is a demo at regex101

在交替使用 [^)(] 而不使用 + 量词之前,如果不平衡会更快地失败。 您需要添加更多可能发生的嵌套级别。例如最多 2 个级别:

\((?:[^)(]|\((?:[^)(]|\([^)(]*\))*\))*\)

Another demo at regex101

【讨论】:

非常好,感谢您的详细解释(赞成)! 我刚刚遇到了类似的情况,并为这个解决方案搜索了很多。感谢您分享这个想法并提供很好的解释。【参考方案3】:

re 匹配是急切的,因此它们会尝试匹配尽可能多的文本,对于您提到的简单测试用例,只需运行正则表达式即可:

>>> re.sub(r'\(.*\)', '', 'stuff(remove(me))')
'stuff'

【讨论】:

@Cleb 请注意,这不会检查大括号是否匹配。例如。在foo(bar)baz(spam)e)ggs 中,它只会留下fooggs @ivan_pozdeev:感谢您的警告,很高兴知道!在我的示例中,它们应该匹配,但我还是会添加一个检查。【参考方案4】:

如果您确定括号最初是平衡的,只需使用 greedy 版本:

re.sub(r'\(.*\)', '', s2)

【讨论】:

【参考方案5】:

https://regex101.com/r/kQ2jS3/1

'(\(.*\))'

这会捕获furthest 括号以及括号之间的所有内容。

您的旧正则表达式捕获第一个括号,以及 next 括号之间的所有内容。

【讨论】:

与其他两个答案相同,但无论如何感谢(赞成)... :)【参考方案6】:

我在这里找到了解决方案:

http://rachbelaid.com/recursive-regular-experession/

上面写着:

>>> import regex
>>> regex.search(r"^(\((?1)*\))(?1)*$", "()()") is not None
True
>>> regex.search(r"^(\((?1)*\))(?1)*$", "(((()))())") is not None
True
>>> regex.search(r"^(\((?1)*\))(?1)*$", "()(") is not None
False
>>> regex.search(r"^(\((?1)*\))(?1)*$", "(((())())") is not None
False

【讨论】:

以上是关于如何删除字符串中外括号之间的所有文本?的主要内容,如果未能解决你的问题,请参考以下文章

C# Regex - 如何从字符串中删除多个成对的括号

删除括号之间的字符串 [iOS]

删除括号之间的文本 PHP

删除字符串中两个字符(括号)之间的文本

删除括号之间的字符

notepad++正则表达式删除大括号之间的所有文本