Книга: PyNEng
Назад: Наборы символов
Дальше: Специальные символы

Символы повторения

Символы повторения

  • regex+ - одно или более повторений предшествующего элемента
  • regex* - ноль или более повторений предшествующего элемента
  • regex? - ноль или одно повторение предшествующего элемента
  • regex{n} - ровно n повторений предшествующего элемента
  • regex{n,m} - от n до m повторений предшествующего элемента
  • regex{n, } - n или более повторений предшествующего элемента

+

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

Например, тут повторение относится к букве a:

In [1]: line = '100     aab1.a1a1.a5d3    FastEthernet0/1'  In [2]: re.search('a+', line).group() Out[2]: 'aa' 

А в этом выражении повторяется строка 'a1':

In [3]: line = '100     aab1.a1a1.a5d3    FastEthernet0/1'  In [4]: re.search('(a1)+', line).group() Out[4]: 'a1a1' 

В выражении (a1)+ скобки используются для того, чтобы указать, что повторение относится к последовательности символов 'a1'.

IP-адрес можно описать выражением \d+\.\d+\.\d+\.\d+. Тут плюс используется, чтобы указать, что цифр может быть несколько. А также встречается выражение \..

Оно необходимо из-за того, что точка является специальным символом (она обозначает любой символ). И чтобы указать, что нас интересует именно точка, надо ее экранировать - поместить перед точкой обратный слеш.

Используя это выражение, можно получить IP-адрес из строки sh_ip_int_br:

In [5]: sh_ip_int_br = 'Ethernet0/1    192.168.200.1   YES NVRAM  up          up'  In [6]: re.search('\d+\.\d+\.\d+\.\d+', sh_ip_int_br).group() Out[6]: '192.168.200.1' 

Еще один пример выражения: \d+\s+\S+ - оно описывает строку, в которой идут цифры, пробел (whitespace), не whitespace символы, то есть, все, кроме пробела, таба и других whitespace символов. С его помощью можно получить VLAN и MAC-адрес из строки:

In [7]: line = '1500     aab1.a1a1.a5d3    FastEthernet0/1'  In [8]: re.search('\d+\s+\S+', line).group() Out[8]: '1500     aab1.a1a1.a5d3' 

*

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

Например, если звездочка стоит после символа, она означает повторение этого символа.

Выражение ba* означает b, а затем ноль или более повторений a:

In [9]: line = '100     a011.baaa.a5d3    FastEthernet0/1'  In [10]: re.search('ba*', line).group() Out[10]: 'baaa' 

Если в строке line до подстроки baaa встретится b, то совпадением будет b:

In [11]: line = '100     ab11.baaa.a5d3    FastEthernet0/1'  In [12]: re.search('ba*', line).group() Out[12]: 'b' 

Допустим, необходимо написать регулярное выражение, которое описывает email'ы двух форматов: [email protected] и [email protected]. То есть, в левой части адреса может быть или одно слово, или два слова, разделенные точкой.

Первый вариант на примере адреса без точки:

In [13]: email1 = '[email protected]' 

Этот адрес можно описать таким выражением \w+@\w+\.\w+:

In [14]: re.search('\w+@\w+\.\w+', email1).group() Out[14]: '[email protected]' 

Но такое выражение не подходит для email с точкой:

In [15]: email2 = '[email protected]'  In [16]: re.search('\w+@\w+\.\w+', email2).group() Out[16]: '[email protected]' 

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

In [17]: re.search('\w+\.\w+@\w+\.\w+', email2).group() Out[17]: '[email protected]' 

Чтобы описать оба варианта адресов, надо указать, что точка в адресе опциональна:

'\w+\.*\w+@\w+\.\w+' 

Такое регулярное выражение описывает оба варианта:

In [18]: email1 = '[email protected]'  In [19]: email2 = '[email protected]'  In [20]: re.search('\w+\.*\w+@\w+\.\w+', email1).group() Out[20]: '[email protected]'  In [21]: re.search('\w+\.*\w+@\w+\.\w+', email2).group() Out[21]: '[email protected]' 

?

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

В этой ситуации логичней использовать знак вопроса. Он обозначает ноль или одно повторение предыдущего выражения или символа. Теперь регулярное выражение выглядит так \w+\.?\w+@\w+\.\w+:

In [22]: mail_log = ['Jun 18 14:10:35 client-ip=154.10.180.10 [email protected], size=551',      ...:             'Jun 18 14:11:05 client-ip=150.10.180.10 [email protected], size=768']  In [23]: for message in mail_log:      ...:     match = re.search('\w+\.?\w+@\w+\.\w+', message)      ...:     if match:      ...:         print("Found email: ", match.group())      ...: Found email:  [email protected] Found email:  [email protected] 

{n}

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

Например, выражение \w{4}\.\w{4}\.\w{4} описывает 12 букв или цифр, которые разделены на три группы по четыре символа точками. Таким образом можно получить MAC-адрес:

In [24]: line = '100     aab1.a1a1.a5d3    FastEthernet0/1'  In [25]: re.search('\w{4}\.\w{4}\.\w{4}', line).group() Out[25]: 'aab1.a1a1.a5d3' 

В фигурных скобках можно указывать и диапазон повторений. Например, попробуем получить все номера VLAN'ов из строки mac_table:

In [26]: mac_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     ...: 1100    a2bb.ec40.7000    DYNAMIC     Gi0/4     ...:  500    aa4b.c550.7000    DYNAMIC     Gi0/5     ...: 1200    a1bb.1c60.7000    DYNAMIC     Gi0/6     ...: 1300    aa0b.cc70.7000    DYNAMIC     Gi0/7     ...: ''' 

Так так search ищет только первое совпадение, в выражение \d{1,4} попадет номер VLAN:

In [27]: for line in mac_table.split('\n'):     ...:     match = re.search('\d{1,4}', line)     ...:     if match:     ...:         print('VLAN: ', match.group())     ...: VLAN:  1 VLAN:  100 VLAN:  200 VLAN:  300 VLAN:  1100 VLAN:  500 VLAN:  1200 VLAN:  1300 

Выражение \d{1,4} описывает от одной до четырех цифр.

Обратите внимание, что в выводе команды нет первого VLAN. Такой результат получился из-за того, что в имени коммутатора есть цифра и она совпала с выражением.

Чтобы исправить это, достаточно дополнить выражение и указать, что после цифр должен идти хотя бы один пробел:

In [28]: for line in mac_table.split('\n'):     ...:     match = re.search('\d{1,4} +', line)     ...:     if match:     ...:         print('VLAN: ', match.group())     ...: VLAN:  100 VLAN:  200 VLAN:  300 VLAN:  1100 VLAN:  500 VLAN:  1200 VLAN:  1300 
Назад: Наборы символов
Дальше: Специальные символы