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