Регулярное выражение для удаления всех знаков препинания и всего, что заключено в квадратные скобки

#python #regex

#python #регулярное выражение

Вопрос:

Я пытаюсь удалить все знаки препинания и все, что находится внутри скобок, из строки в python. Идея состоит в том, чтобы несколько нормализовать названия песен, чтобы получить лучшие результаты при запросе веб-сервиса MusicBrainz.

Пример ввода: T.N.T. (live) [nyc]

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

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

 >>> re.sub(r'[.*?]|(.*?)|W ', ' ', 'T.N.T. (live) [nyc]')
'T N T live nyc '
  

Если я разделю W на его собственное регулярное выражение и выполню его вторым, я получу ожидаемый результат, поэтому кажется, что W фигурные скобки и скобки в скобках используются до того, как с ними справятся первые два варианта.

Комментарии:

1. Вас беспокоят несогласованные скобки или несколько скобок одного типа (возможно, как часть оригинального названия)? Например, каким должен быть результат для входных данных T.N.T. (live (должен live остаться?) и T.N.T. (live) X (nyc) (должен X остаться)?

2. На данный момент я не беспокоюсь о несопоставимых или вложенных скобках. Я думаю, что они, вероятно, не будут появляться достаточно часто, чтобы вызвать большую проблему.

Ответ №1:

Вы правы, что W использует фигурные скобки, удалите , и вы должны быть установлены:

 >>> re.sub(r'[.*?]|(.*?)|W', ' ', 'T.N.T. (live) [nyc]')
'T N T     '
  

Ответ №2:

Вот мини-анализатор, который делает то же самое, что я написал в качестве упражнения. Если ваши усилия по нормализации становятся намного сложнее, вы можете начать искать решения на основе синтаксического анализа. Это работает как крошечный синтаксический анализатор.

 # Remove all non-word chars and anything between parens or brackets

def consume(I):

   I = iter(I)
   lookbehind = None

   def killuntil(returnchar):
      while True:
         ch = I.next()
         if ch == returnchar:
            return

   for i in I:
      if i in 'abcdefghijklmnopqrstuvwyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
         yield i
         lookbehind = i
      elif not i.strip() and lookbehind != ' ':
         yield ' '
         lookbehind = ' '
      elif i == '(': 
         killuntil(')')
      elif i == '[': 
         killuntil(']')
      elif lookbehind != ' ':
         lookbehind = ' '
         yield ' '

s = "T.N.T. (live) [nyc]"
c = consume(s)
  

Комментарии:

1. В качестве дополнительного примечания, string.letters=='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' . Итак import string и сэкономьте время на вводе текста.

Ответ №3:

W Использует квадратные скобки, потому что у него «есть запуск»: он начинает сопоставление с точки после второго T и совпадает до первой круглой скобки включительно: . ( . После этого он снова начинает сопоставление от скобки к скобке: ) [ .

Ответ №4:

W

Если флаги LOCALE и UNICODE не указаны, соответствует любому не алфавитно-цифровому символу; это эквивалентно набору [^a-zA-Z0-9_].

Так что попробуйте r'[.*?]|(.*?)|{.*?}|[^a-zA-Z0-9_()[]{}] ' .

Хотя решение Эндрю, вероятно, лучше.