• ru
  • Language: en
  • Documentation version: latest

Флаги

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

Модуль re поддерживает такие флаги (в скобках короткий вариант обозначения флага):

  • re.ASCII (re.A)

  • re.IGNORECASE (re.I)

  • re.MULTILINE (re.M)

  • re.DOTALL (re.S)

  • re.VERBOSE (re.X)

  • re.LOCALE (re.L)

  • re.DEBUG

В этом подразделе для примера рассматривается флаг re.DOTALL. Информация об остальных флагах доступна в документации.

re.DOTALL

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

Например, из строки sh_cdp надо получить имя устройства, платформу и IOS:

In [2]: sh_cdp = '''
   ...: Device ID: SW2
   ...: Entry address(es):
   ...:   IP address: 10.1.1.2
   ...: Platform: cisco WS-C2960-8TC-L,  Capabilities: Switch IGMP
   ...: Interface: GigabitEthernet1/0/16,  Port ID (outgoing port): GigabitEthernet0/1
   ...: Holdtime : 164 sec
   ...:
   ...: Version :
   ...: Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(55)SE9, RELEASE SOFTWARE (fc1)
   ...: Technical Support: http://www.cisco.com/techsupport
   ...: Copyright (c) 1986-2014 by Cisco Systems, Inc.
   ...: Compiled Mon 03-Mar-14 22:53 by prod_rel_team
   ...:
   ...: advertisement version: 2
   ...: VTP Management Domain: ''
   ...: Native VLAN: 1
   ...: Duplex: full
   ...: Management address(es):
   ...:   IP address: 10.1.1.2
   ...: '''

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

В этом выражении описаны строки с нужными данными:

In [3]: regex = r'Device ID: (\S+).+Platform: \w+ (\S+),.+Cisco IOS Software.+ Version (\S+),'

В таком случае, совпадения не будет, потому что по умолчанию точка означает любой символ, кроме перевода строки:

In [4]: print(re.search(regex, sh_cdp))
None

Изменить поведение по умолчанию, можно с помощью флага re.DOTALL:

In [5]: match = re.search(regex, sh_cdp, re.DOTALL)

In [6]: match.groups()
Out[6]: ('SW2', 'WS-C2960-8TC-L', '12.2(55)SE9')

Так как теперь в точку входит и перевод строки, комбинация .+ захватывает все, между нужными данными.

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

Поиск всех совпадений с регулярным выражением:

In [7]: with open('sh_cdp_neighbors_sw1.txt') as f:
   ...:     sh_cdp = f.read()
   ...:

In [8]: regex = r'Device ID: (\S+).+Platform: \w+ (\S+),.+Cisco IOS Software.+ Version (\S+),'

In [9]: match = re.finditer(regex, sh_cdp, re.DOTALL)

In [10]: for m in match:
    ...:     print(m.groups())
    ...:
('SW2', '2911', '15.2(2)T1')

На первый взгляд, кажется, что вместо трех устройств, в вывод попало только одно. Однако, если присмотреться к результатам, окажется, что кортеже находится Device ID от первого соседа, а платформа и IOS от последнего.

Короткий вариант вывода, чтобы легче было ориентироваться в результатах:

Device ID        Local Intrfce     Holdtme    Capability  Platform  Port ID
SW2              Gi 1/0/16         171              R S   C2960     Gi 0/1
R1               Gi 1/0/22         158              R     C3825     Gi 0/0
R2               Gi 1/0/21         177              R     C2911     Gi 0/0

Так получилось из-за того, что между нужными частями вывода, указана комбинация .+. Без флага re.DOTALL такое выражение захватило бы все до перевода строки, но с флагом оно захватывает максимально длинный кусок текста, так как + жадный. В итоге регулярное выражение описывает строку от первого Device ID до последнего места где встречается Cisco IOS Software.+ Version.

Такая ситуация возникает очень часто при использовании re.DOTALL и чтобы исправить ее, надо не забыть отключить жадность:

In [10]: regex = r'Device ID: (\S+).+?Platform: \w+ (\S+),.+?Cisco IOS Software.+? Version (\S+),'

In [11]: match = re.finditer(regex, sh_cdp, re.DOTALL)

In [12]: for m in match:
    ...:     print(m.groups())
    ...:
('SW2', 'WS-C2960-8TC-L', '12.2(55)SE9')
('R1', '3825', '12.4(24)T1')
('R2', '2911', '15.2(2)T1')