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

4uqofj5v  于 2023-11-20  发布在  其他
关注(0)|答案(7)|浏览(132)

当我有一个这样的字符串:

s1 = 'stuff(remove_me)'

字符串
我可以很容易地删除括号和文本内使用

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


如所解释的here
但我有时会遇到这样的嵌套表达式:

s2 = 'stuff(remove(me))'


当我从上面运行这个命令时,

'stuff)'


我也试过:

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


这给了我相同的输出。
我怎样才能删除外括号内的所有内容--包括括号本身--从而也得到'stuff'(它应该适用于任意复杂的表达式)?

hgtggwj0

hgtggwj01#

注意事项\(.*\)匹配从左起的第一个(,然后匹配任何0+字符(如果没有启用DOTALL修饰符,则不匹配换行符),直到 last),并且不考虑正确嵌套的括号。
要在Python中正确地使用正则表达式删除嵌套括号,可以在 while 块中使用re.subn,使用简单的\([^()]*\)(匹配(,然后匹配()之外的0+字符,然后匹配)):

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

cgyqldqp

cgyqldqp2#

如前所述,你需要一个recursive regex来匹配任意层次的嵌套,但是如果你知道最多只能有一个层次的嵌套,那么试试这个模式:

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

字符串

  • [^)(]匹配一个字符,它不是括号(否定类)。
  • |\([^)(]*\)或者它匹配另一个()对,其中包含任意数量的 non)(
  • (?: ... )*所有这些在()内部的任何次数

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

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


Another demo at regex101

stszievb

stszievb3#

re匹配是急切的,所以他们试图匹配尽可能多的文本,对于你提到的简单测试用例,只是让正则表达式运行:

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

字符串

fxnxkyjh

fxnxkyjh4#

如果你确定括号一开始是平衡的,就使用 greedy 版本:

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

字符串

bvn4nwqk

bvn4nwqk5#

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

'(\(.*\))'

字符串
这将捕获furthest括号以及括号之间的所有内容。
旧的正则表达式捕获第一个括号,以及next括号之间的所有内容。

laik7k3q

laik7k3q6#

我在这里找到了一个解决方案:
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

字符串

jjjwad0x

jjjwad0x7#

没有Python循环。没有递归。没有正则表达式。

计算'('')'的累积计数之间的差:

import numpy as np
s = '()a(x(x)x)b(x)c()d()'
s_array = np.array(list(s))
mask_open = s_array=='('
mask_close = s_array==')'
# Compute in how many parentheses each character is nested,
# while considering ')' as not nested:
nestedness_except_close = np.cumsum(mask_open) - np.cumsum(mask_close)
# ... and while considering ')' as nested:
nestedness = nestedness_except_close + mask_close
# Select only characters that aren't in any parentheses
result = ''.join(s_array[nestedness < 1])

字符串
这可能比其他解决方案更快。
可选的字符串有效性检查:

# Check whether the number of `'('`s and `')'`s is the same
assert(nestedness_except_close[-1] == 0)
# Check whether some parentheses get closed before they got opened
assert((nestedness_except_close >= 0).all())


如果你不想使用NumPy,你可以使用itertools.accumulate()来计算累计和。

相关问题