Удалить текст между () и [] в Python

У меня есть очень длинная строка текста с () а также [] в этом. Я пытаюсь удалить символы между скобками и скобками, но не могу понять, как это сделать.

Список похож на это:

x = "This is a sentence. (once a day) [twice a day]"

Этот список не тот, с которым я работаю, но он очень похож и намного короче.

Спасибо за помощь.

9 ответов

Решение

Это должно работать для паренов. регулярные выражения будут "потреблять" соответствующий текст, поэтому не будут работать с вложенными паренами.

import re
regex = re.compile(".*?\((.*?)\)")
result = re.findall(regex, mystring)

или это найдет один набор паренов... просто цикл, чтобы найти больше

start = mystring.find( '(' )
end = mystring.find( ')' )
if start != -1 and end != -1:
  result = mystring[start+1:end]

Вы можете использовать функцию re.sub.

>>> import re 
>>> x = "This is a sentence. (once a day) [twice a day]"
>>> re.sub("([\(\[]).*?([\)\]])", "\g<1>\g<2>", x)
'This is a sentence. () []'

Если вы хотите удалить [] и (), вы можете использовать этот код:

>>> import re 
>>> x = "This is a sentence. (once a day) [twice a day]"
>>> re.sub("[\(\[].*?[\)\]]", "", x)
'This is a sentence.  '

Важно: этот код не будет работать с вложенными символами

Запустите этот скрипт, он работает даже с вложенными скобками.
Использует базовые логические тесты.

def a(test_str):
    ret = ''
    skip1c = 0
    skip2c = 0
    for i in test_str:
        if i == '[':
            skip1c += 1
        elif i == '(':
            skip2c += 1
        elif i == ']' and skip1c > 0:
            skip1c -= 1
        elif i == ')'and skip2c > 0:
            skip2c -= 1
        elif skip1c == 0 and skip2c == 0:
            ret += i
    return ret

x = "ewq[a [(b] ([c))]] This is a sentence. (once a day) [twice a day]"
x = a(x)
print x
print repr(x)

Просто если вы не запускаете его,
Вот вывод:

>>> 
ewq This is a sentence.  
'ewq This is a sentence.  ' 

Вот решение, похожее на ответ @pradyunsg (оно работает с произвольными вложенными скобками):

def remove_text_inside_brackets(text, brackets="()[]"):
    count = [0] * (len(brackets) // 2) # count open/close brackets
    saved_chars = []
    for character in text:
        for i, b in enumerate(brackets):
            if character == b: # found bracket
                kind, is_close = divmod(i, 2)
                count[kind] += (-1)**is_close # `+1`: open, `-1`: close
                if count[kind] < 0: # unbalanced bracket
                    count[kind] = 0  # keep it
                else:  # found bracket to remove
                    break
        else: # character is not a [balanced] bracket
            if not any(count): # outside brackets
                saved_chars.append(character)
    return ''.join(saved_chars)

print(repr(remove_text_inside_brackets(
    "This is a sentence. (once a day) [twice a day]")))
# -> 'This is a sentence.  '

Вы можете разделить, отфильтровать и снова присоединить строку. Если ваши скобки четко определены, подойдет следующий код.

      import re
x = "".join(re.split("\(|\)|\[|\]", x)[::2])

Вы можете попробовать это. Можно удалить скобку, и внутри нее будет существовать содержимое.

       import re
    x = "This is a sentence. (once a day) [twice a day]"
    x = re.sub("\(.*?\)|\[.*?\]","",x)
    print(x)

Ожидаемый результат:

      This is a sentence. 

Для тех, кто ценит простоту принятого ответа jvallver и ищет более читабельный код:

      >>> import re
>>> x = 'This is a sentence. (once a day) [twice a day]'
>>> opening_braces = '\(\['
>>> closing_braces = '\)\]'
>>> non_greedy_wildcard = '.*?'
>>> re.sub(f'[{opening_braces}]{non_greedy_wildcard}[{closing_braces}]', '', x)
'This is a sentence.  '

Большая часть объяснения того, почему это регулярное выражение работает, включена в код. Ваше будущее «я» поблагодарит вас за 3 дополнительные строки.

(Замените f-строку на эквивалентную конкатенацию строк для совместимости с Python2)

регулярное выражение\(.*?\)|\[.*?\]удаляет содержимое скобок, находя пары, сначала удаляет скобки, а затем квадратные скобки. I также отлично работает для вложенных скобок, поскольку действует последовательно. Конечно, это сломается в случае сценария с плохими скобками.

      
    _brackets = re.compile("\(.*?\)|\[.*?\]")
    _spaces = re.compile("\s+")
    
    _b = _brackets.sub(" ", "microRNAs (miR) play a role in cancer ([1], [2])")
    _s = _spaces.sub(" ", _b.strip())
    print(_s)
    
    # OUTPUT: microRNAs play a role in cancer

Решение без регулярного выражения, которое не заботится о сбалансированных круглых скобках (слева направо соответствует ближайшей открытой закрывающей паре) и добавляет остатки в конец, если они незакрыты, и немедленно начинает удалять символы, если они находятся после открывающих круглых скобок, независимо от их числа. предыдущих закрывающихся скобок.

      def removeparenthesis(input_str, open_p="(", close_p=")"):
    result = ''
    remainder = ''
    paren_level = 0
    for ch in input_str:
        if ch in open_p:
            if paren_level < 0:
                paren_level = 1
            else:
                paren_level += 1
        elif ch in close_p:
            paren_level -= 1
            remainder = ''
        elif 0 >= paren_level:
            result += ch
        else:
            remainder += ch
    return result + remainder

Я считаю, что это немного более естественно, чем заставлять все быть сбалансированным. Сделаны очень закрывающие круглые скобки для игнорирования в тексте в обычном режиме.

Полезно, если ваш вариант использования удаляет круглые скобки и их содержимое, чтобы не остаться неуклюжими, не имеющими себе равных. «Безопасный» способ вызвать это, вероятно, - это два вызова, один для каждой пары, а не один для обеих пар, поскольку я не нашел способа, который мне нравился бы делать оба без сопоставления (] или аналогичного, даже если опция там.

Другие вопросы по тегам