Группа без захвата

По умолчанию все, что попало в группу, запоминается. Это называется группа с захватом.

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

Например, надо получить MAC-адрес, VLAN и порты из такого лог-сообщения:

In [1]: log = 'Jun  3 14:39:05.941: %SW_MATM-4-MACFLAP_NOTIF: Host f03a.b216.7ad7 in vlan 10 is flapping between port Gi0/5 and port Gi0/15'

Регулярное выражение, которое описывает нужные подстроки:

In [2]: match = re.search(r'((\w{4}\.){2}\w{4}).+vlan (\d+).+port (\S+).+port (\S+)', log)

Выражение состоит из таких частей:

  • ((\w{4}\.){2}\w{4}) - сюда попадет MAC-адрес
  • \w{4}\. - эта часть описывает 4 буквы или цифры и точку
  • (\w{4}\.){2} - тут скобки нужны, чтобы указать, что 4 буквы или цифры и точка повторяются два раза
  • \w{4} - затем 4 буквы или цифры
  • .+vlan (\d+) - в группу попадет номер VLAN
  • .+port (\S+) - первый интерфейс
  • .+port (\S+) - второй интерфейс

Метод groups вернет такой результат:

In [3]: match.groups()
Out[3]: ('f03a.b216.7ad7', 'b216.', '10', 'Gi0/5', 'Gi0/15')

Второй элемент, по сути, лишний. Он попал в вывод из-за скобок в выражении (\w{4}\.){2}.

В этом случае нужно отключить захват в группе. Это делается добавлением ?: после открывающейся скобки группы.

Теперь выражение выглядит так:

In [4]: match = re.search(r'((?:\w{4}\.){2}\w{4}).+vlan (\d+).+port (\S+).+port (\S+)', log)

И, соответственно, группы:

In [5]: match.groups()
Out[5]: ('f03a.b216.7ad7', '10', 'Gi0/5', 'Gi0/15')