Книга: PyNEng
Назад: Жадность символов повторения
Дальше: Группа без захвата

Группировка выражений

Группировка выражений

Группировка выражений указывает, что последовательность символов надо рассматривать как одно целое. Но это не единственное преимущество группировки.

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

Например, из log-файла надо отобрать строки, в которых встречается "%SW_MATM-4-MACFLAP_NOTIF", а затем из каждой такой строки получить MAC-адрес, VLAN и интерфейсы. В этом случае регулярное выражение просто должно описывать строку, а все части строки, которые надо получить в результате, просто заключаются в скобки.

В Python есть два варианта использования групп:

  • Нумерованные группы
  • Именованные группы

Нумерованные группы

Группа определяется помещением выражения в круглые скобки ().

Внутри выражения группы нумеруются слева направо, начиная с 1.
Затем к группам можно обращаться по номерам и получать текст, который соответствует выражению в группе.

Пример использования групп:

In [8]: line = "FastEthernet0/1            10.0.12.1       YES manual up                    up" In [9]: match = re.search('(\S+)\s+([\w.]+)\s+.*', line) 

В данном примере указаны две группы:

  • первая группа - любые символы, кроме whitespaces
  • вторая группа - любая буква или цифра (символ \w) или точка

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

Теперь можно обращаться к группам по номеру. Группа 0 - это строка, которая соответствует всему шаблону:

In [10]: match.group(0) Out[10]: 'FastEthernet0/1            10.0.12.1       YES manual up                    up'  In [11]: match.group(1) Out[11]: 'FastEthernet0/1'  In [12]: match.group(2) Out[12]: '10.0.12.1' 

При необходимости можно перечислить несколько номеров групп:

In [13]: match.group(1, 2) Out[13]: ('FastEthernet0/1', '10.0.12.1')  In [14]: match.group(2, 1, 2) Out[14]: ('10.0.12.1', 'FastEthernet0/1', '10.0.12.1') 

Начиная с версии Python 3.6, к группам можно обращаться таким образом:

In [15]: match[0] Out[15]: 'FastEthernet0/1            10.0.12.1       YES manual up                    up'  In [16]: match[1] Out[16]: 'FastEthernet0/1'  In [17]: match[2] Out[17]: '10.0.12.1' 

Для вывода всех подстрок, которые соответствуют указанным группам, используется метод groups:

In [18]: match.groups() Out[18]: ('FastEthernet0/1', '10.0.12.1') 

Именованные группы

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

Именованные группы позволяют задавать группе имя.

Синтаксис именованной группы (?P<name>regex):

In [19]: line = "FastEthernet0/1            10.0.12.1       YES manual up                    up"  In [20]: match = re.search('(?P<intf>\S+)\s+(?P<address>[\d.]+)\s+', line) 

Теперь к этим группам можно обращаться по имени:

In [21]: match.group('intf') Out[21]: 'FastEthernet0/1'  In [22]: match.group('address') Out[22]: '10.0.12.1' 

Также очень полезно то, что с помощью метода groupdict(), можно получить словарь, где ключи - имена групп, а значения - подстроки, которые им соответствуют:

In [23]: match.groupdict() Out[23]: {'address': '10.0.12.1', 'intf': 'FastEthernet0/1'} 

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

In [24]: match = re.search('(?P<intf>\S+)\s+(?P<address>[\d\.]+)\s+\w+\s+\w+\s+(?P<status>up|down|administratively down)\s+(?P<protocol>up|down)', line)  In [25]: match.groupdict() Out[25]: {'address': '10.0.12.1',  'intf': 'FastEthernet0/1',  'protocol': 'up',  'status': 'up'} 
Назад: Жадность символов повторения
Дальше: Группа без захвата