(Regex Python) удалить конструкции в квадратных скобках в строке

Рейтинг: 1Ответов: 3Опубликовано: 08.01.2023

Пусть на вход дана строка, в которой есть комментарии автора, записанные в квадратных скобках.

Например, так: Это отличная строка [по моему мнению]

Или даже так: [Сейчас бы погладить [милого] ёжика] Это прекрасная [ну или не очень] строка

Комментарии автора не нужны конечному пользователю – значит, их можно удалить и получить такие строки:

Это отличная строка

Это прекрасная строка

Реализуйте программу, удаляющую скобки и комментарии внутри них.

С первой строкой я справился, а со второй - не пойму как быть, не могу подобрать паттерн

import re
str1, str2 = 'Это отличная строка [по моему мнению]', \
             '[Сейчас бы погладить [милого] ёжика] Это прекрасная [ну или не очень] строка'

pattern1 = r'\[.+\]'
pattern2 = r''
print(re.sub(pattern1, '', str1))
print(re.sub(pattern2, '', str2))

Ответы

▲ -1Принят

Для нескольких вложенных скобок в предложении можно воспользоваться просмотром вперед. И если за закрывающей квадратной скобкой следует опять закрывающая, то продолжаем брать до неё.

import re

str1, str2 = 'Это отличная строка [по моему мнению]', \
             '[Сейчас бы погладить [милого] ёжика] Это прекрасная [ну или не очень] строка'

pattern = r'\[.*?\] *(?![\w\s]*?\])'

print(re.sub(pattern, '', str1))
print(re.sub(pattern, '', str2))

--------------------------
Это отличная строка 
Это прекрасная строка

Проверить можно здесь.

\[ соответствует символу [ с индексом 9110 (5B16 или 1338) буквально (с учетом регистра)
. соответствует любому символу (кроме разделителей строк)
*? соответствует предыдущему токену от нуля до неограниченного количества раз, как можно меньше раз, расширяясь по мере необходимости (ленивый)
\] буквально соответствует символу ] с индексом 9310 (5D16 или 1358) (с учетом регистра)
   буквально соответствует символу с индексом 3210 (2016 или 408) (с учетом регистра)
* соответствует предыдущему токену от нуля до неограниченного количества раз, как можно больше раз, возвращая по мере необходимости (жадный)
Отрицательный просмотр вперед (?![\w\s]*?\])
Утверждают, что приведенное ниже регулярное выражение не соответствует
Совпадение с одним символом из списка ниже [\w\s]
*? соответствует предыдущему токену от нуля до неограниченного количества раз, как можно меньше раз, расширяясь по мере необходимости (ленивый)
\w соответствует любому символу слова (эквивалентно [a-zA-Z0-9_])
\s соответствует любому символу пробела (эквивалентен [\r\n\t\f\v ])
\] буквально соответствует символу ] с индексом 9310 (5D16 или 1358) (с учетом регистра)]
▲ 1

Код работает, если только нет лишних "одиноких" символов "[" или "]"

import re
str1, str2 = 'Это отличная строка [по моему мнению]', \
         '[Сейчас бы погладить [милого] ёжика] Это прекрасная [ну или не очень] строка'
pattern = r'\[[^\[\]]*\]'

print(re.sub(pattern, '', str1))

for i in range(str2.count('[')):
    str2 = re.sub(pattern, '', str2)
print(re.sub(' +', ' ', str2).strip())

Вывод:

>>> Это отличная строка 
>>> Это прекрасная строка
▲ 1

Нужно удалять все подстроки между скобками до тех пор, пока не останется ни одного совпадения.

Код:

import re

def remove_text_between_brackets(text):
    n = 1
    while n:
        text, n = re.subn(r'\s*\[[^][]*]', '', text)
    return text.strip()

С помощью \s* перед \[[^][]*] находятся (и потом удаляются) все пробельные символы перед подстрокой между скобками.

Тест (см. пример выполнения кода):

texts = ['Это отличная строка [по моему мнению]', '[Сейчас бы погладить [милого] ёжика] Это прекрасная [ну или не очень] строка']
for text in texts:
    print(remove_text_between_brackets(text))

Результат:

Это отличная строка
Это прекрасная строка