- en
- Language: ru
- Documentation version: latest
Группировка выражений
Группировка выражений указывает, что последовательность символов надо рассматривать как одно целое. Однако это не единственное преимущество группировки.
Кроме этого, с помощью групп можно получать только определенную часть строки, которая была описана выражением. Это очень полезно в ситуациях, когда надо описать строку достаточно подробно, чтобы отобрать нужные строки, но в то же время из самой строки надо получить только определенное значение.
Например, из 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)
В данном примере указаны две группы:
первая группа - любые символы, кроме пробельных
вторая группа - любая буква или цифра (символ
\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)\s+(?P<protocol>up|down)', line)
In [25]: match.groupdict()
Out[25]:
{'address': '10.0.12.1',
'intf': 'FastEthernet0/1',
'protocol': 'up',
'status': 'up'}