Книга: PyNEng
Назад: re.finditer
Дальше: re.compile

re.findall

re.findall()

Функция findall():

  • используется для поиска всех непересекающихся совпадений в шаблоне
  • возвращает:
    • список строк, которые описаны регулярным выражением, если в регулярном выражении нет групп
    • список строк, которые совпали с регулярным выражением в группе, если в регулярном выражении одна группа
    • список кортежей, в которых находятся строки, которые совпали с выражением в группе, если групп несколько

Рассмотрим работу findall на примере вывода команды sh mac address-table:

In [2]: mac_address_table = open('CAM_table.txt').read()  In [3]: print(mac_address_table) sw1#sh mac address-table           Mac Address Table -------------------------------------------  Vlan    Mac Address       Type        Ports ----    -----------       --------    -----  100    a1b2.ac10.7000    DYNAMIC     Gi0/1  200    a0d4.cb20.7000    DYNAMIC     Gi0/2  300    acb4.cd30.7000    DYNAMIC     Gi0/3  100    a2bb.ec40.7000    DYNAMIC     Gi0/4  500    aa4b.c550.7000    DYNAMIC     Gi0/5  200    a1bb.1c60.7000    DYNAMIC     Gi0/6  300    aa0b.cc70.7000    DYNAMIC     Gi0/7 

Первый пример - регулярное выражение без групп. В этом случае findall возвращает список строк, которые совпали с регулярным выражением.

Например, с помощью findall можно получить список строк с соответствиями vlan - mac - interface и избавиться от заголовка в выводе команды:

In [4]: re.findall('\d+ +\S+ +\w+ +\S+', mac_address_table) Out[4]: ['100    a1b2.ac10.7000    DYNAMIC     Gi0/1',  '200    a0d4.cb20.7000    DYNAMIC     Gi0/2',  '300    acb4.cd30.7000    DYNAMIC     Gi0/3',  '100    a2bb.ec40.7000    DYNAMIC     Gi0/4',  '500    aa4b.c550.7000    DYNAMIC     Gi0/5',  '200    a1bb.1c60.7000    DYNAMIC     Gi0/6',  '300    aa0b.cc70.7000    DYNAMIC     Gi0/7'] 

Обратите внимание, что findall возвращает список строк, а не объект Match.

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

Если в выражении используется одна группа, findall возвращает список строк, которые совпали с выражением в группе:

In [5]: re.findall('\d+ +(\S+) +\w+ +\S+', mac_address_table) Out[5]: ['a1b2.ac10.7000',  'a0d4.cb20.7000',  'acb4.cd30.7000',  'a2bb.ec40.7000',  'aa4b.c550.7000',  'a1bb.1c60.7000',  'aa0b.cc70.7000'] 

При этом findall ищет совпадение всей строки, но возвращает результат, похожий на метод groups() в объекте Match.

Если же групп несколько, findall вернет список кортежей:

In [6]: re.findall('(\d+) +(\S+) +\w+ +(\S+)', mac_address_table) Out[6]: [('100', 'a1b2.ac10.7000', 'Gi0/1'),  ('200', 'a0d4.cb20.7000', 'Gi0/2'),  ('300', 'acb4.cd30.7000', 'Gi0/3'),  ('100', 'a2bb.ec40.7000', 'Gi0/4'),  ('500', 'aa4b.c550.7000', 'Gi0/5'),  ('200', 'a1bb.1c60.7000', 'Gi0/6'),  ('300', 'aa0b.cc70.7000', 'Gi0/7')] 

Если такие особенности работы функции findall мешают получить необходимый результат, то лучше использовать фукнцию finditer. Но иногда такое поведение подходит и удобно использовать.

Пример использования findall в разборе лог-файла (файл parse_log_findall.py):

import re  regex = ('Host \S+ '          'in vlan (\d+) '          'is flapping between port '          '(\S+) and port (\S+)')  ports = set()  with open('log.txt') as f:     result = re.findall(regex, f.read())     for vlan, port1, port2 in result:         ports.add(port1)         ports.add(port2)  print('Петля между портами {} в VLAN {}'.format(', '.join(ports), vlan)) 

Результат:

$ python parse_log_findall.py Петля между портами Gi0/19, Gi0/16, Gi0/24 в VLAN 10 
Назад: re.finditer
Дальше: re.compile