⽹络⼯程师——正则表达式(模糊匹配)
⽹络⼯程师——正则表达式(模糊匹配)
(本博客借鉴《⽹络⼯程师的python之路这本书》
1.什么是正则表达式
  正则表达式,⼜称规则表达式,计算机科学的⼀个概念。正则表达式通常被⽤来检索、替换那些符合某个模式(规则)的⽂本。
  许多程序设计语⾔都⽀持利⽤正则表达式进⾏字符串操作。例如,在Perl中就内建了⼀个功能强⼤的正则表达式引擎。正则表达式这个概念最初是由Unix中的⼯具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。
(来源百度百科)
2.正则表达式的规则(模糊匹配)
匹配
符号
⽤法
.匹配除换⾏符之外的所有字符(⼀次)
*⽤来匹配紧靠该符号左边的符号,匹配次数0次或多次。
+⽤来匹配紧靠该符号左边的符号,匹配次数1次或多次。
⽤来匹配紧靠该符号左边的符号,匹配次数0次或1次。
{m}⽤来匹配紧靠该符号左边的符号,指定匹配次数为m次,例如字符串’abbbbcccd’,使⽤ab{2}将匹配到abb,使⽤bc{3}d将匹配到bcccd。
{m,n}⽤来匹配紧靠该符号左边的符号,指定匹配次数为最少m次,最多n次。 例如字符串’abbcccd’,使⽤ab{2,3}将只能匹配到abb,如果字符串为’abbbbcccdabbccd’,使⽤ab{2,3}将能同时匹配到abbb和abb。如果字符串内容为’abcd’使⽤ab{2,3}将匹配不到任何东西。
{m,}⽤来匹配紧靠该符号左边的符号,指定匹配次数为最少m次,最多⽆限次。
{,n}⽤来匹配紧靠该符号左边的符号,指定匹配次数为最少0次,最多n次。
\例如字符串内容中出现了问号"?”,⽽你⼜想精确匹配这个问号,那就要使⽤?来进⾏匹配。除此之外,\也⽤来表⽰⼀个特殊序列。
[]表⽰字符集合,⽤来精确匹配。⽐如想要精确匹配⼀个数字,可以使⽤[0-9]。如果要精确匹配⼀个⼩写字母,可以⽤[a-z],如果要精确匹配⼀个⼤写字母,可以⽤[A-Z],如果要匹配⼀个数字、字母或者下划线,可以⽤[0-9a-zA-Z_]。另外在[]中加^表⽰取⾮,⽐如[^O-9]表⽰匹配⼀个⾮数字的字符,[^a-z]表⽰匹配⼀个⾮字母的字符,以此类推。
|表⽰或匹配(两项中匹配其中任意⼀项),⽐如要匹配FastEthernet和GigabitEthernet这两种端⼝名,可以写作Fa|Gi。(…)组合,匹配括号内的任意正则表达式,并标识出组合的开始和结尾,例如(blcd)ef表⽰bef或cdef。
\d匹配任意⼀个⼗进制数字,等价于[0-9]
\D ld取⾮,匹配任意⼀个⾮⼗进制数字,等价于[^0-9]
\w匹配任意⼀个字母,⼗进制数字以及下划线,等价于[a-zA-Z0-9_]
\W匹配任意个⼀个空⽩字符,包括空格,换⾏符\n等等。
\s匹配任意个⼀个空⽩字符,包括空格,换⾏符\n等等。
在使⽤表达式之前⼀定要先import re
2.1[]的应⽤
>>> re.match('a[a-z]c',`在这⾥插⼊代码⽚`'abc')
<re.Match object; span=(0,3), match='abc'>匹配a-z之间任意字符
>>> re.match('a[a-z]c','a1c')
>>> re.match('a[0-9]c','a1c')
<re.Match object; span=(0,3), match='a1c'>匹配0-9之间任意字符
>>> re.match('a[^a-z]c','a1c')
<re.Match object; span=(0,3), match='a1c'>匹配除了a-z之间任意
2.2* ?()的应⽤
>>> re.match('ba(na)?','ba')
<re.Match object; span=(0,2), match='ba'>
>>> re.match('ba(na)?','bana')
<re.Match object; span=(0,4), match='bana'>
>>> re.match('ba(na)?','banana')
<re.Match object; span=(0,4), match='bana'>
>>> re.match('ba(na)*','ba')
<re.Match object; span=(0,2), match='ba'>
>>> re.match('ba(na)*','bana')
<re.Match object; span=(0,4), match='bana'>
>>> re.match('ba(na)*','banana')
<re.Match object; span=(0,6), match='banana'>
总结:?0或1*0或⽆穷
2.3 |的应⽤
>>> re.match('root|Root','root')
<re.Match object; span=(0,4), match='root'>
regex匹配>>> re.match('root|Root','Root')
<re.Match object; span=(0,4), match='Root'>
2.4贪婪匹配
  *, +,?,{m}, {m,}, {m,n}这六种匹配符号默认都是贪婪匹配的,即会尽可能多的去匹配符合条件的内容。举例如下:
举例如下:
  假设给定的字符串为’xxzyzyz’,我们使⽤正则表达式x.*y来做匹配(注:精确匹配和模糊匹配可以混⽤)。在匹配到第⼀个x后,开始匹配.*,因为.和*默认是贪婪匹配,这⾥它会⼀直往后匹配,直到匹配到最后⼀个y,因此这⾥的匹配结果为xxzyzy。
2.5⾮贪婪匹配
  要实现⾮贪婪匹配很简单,就是在上述六种贪婪匹配符号后⾯加上问号?即可,也即是*?, +?, ??, {m}?, {m,}?, {m,n}?。
因为.*?是⾮贪婪匹配,这⾥它在匹配到第⼀个y后便随即停⽌,因此这⾥的匹配结果为xxzy。
可以认为是对于后⾯的字符⽣效,只要匹配到⼀次后⾯的字符就结束匹配
2.6实例
匹配思科交换机中⽇志类型\w{1,9}-\d-\w{6,13}
000459: Feb 1717:10:35.202:%LINK-3-UPDOWN: Interface FastEthernet0/2, changed state to up
000460: Feb 1717:10:36.209:%LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/2, changed state to up
000461: Feb 1722:39:26.464:%SSH-5-SSH2_SESSION: SSH2 Session request from10.1.1.1(tty =0) using crypto cipher 'aes128-cbc', hmac 'hmac-sha 1' Succeeded
000462: Feb 1722:39:27.748:%SSH-5-SSH2_USERAUTH: User 'test' authentication for SSH2 Session from10.1.1.1(tty =0) using crypto cipher 'aes128-cbc', hmac 'hmac-sha1' Succeeded
⽤LINK-3-UPDOWN举例
%:匹配%
w{1,9}:匹配 link
-:匹配-
\d:匹配3
w{6,13}:匹配 UPDOWN
3 各种⽅法
3.1 re.mach()
(前⽂已经⽤过了)
  这⾥我们使⽤re.match()函数,从字符" Test match() function of regular expression. "⾥去精确匹配模式’Test’,因
为’Test’位于该段字符串的起始位置,所以匹配成功,并且返回了⼀个匹配到的对象<re.Match object; span=(0, 4),
match=‘Test’>,为了查看该对象的具体的值,我们可以对该对象调⽤group()⽅法,得到具体的值’Test’,该值的数据类型为字符串。
import re
test='Test match() function or regular expression.'
a=re.match(r"Test",test)
print(a)
up())
输出:
<re.Match object; span=(0,4), match='Test'>
Test
  如果这⾥我们不从字符串的起始位置去匹配,⽽是去匹配中间或末尾的字符串内容的话,那么re.match()将匹配不到任何东西,从⽽返回None,⽐如这⾥我们去匹配’function’这个词,因为function
不在’Test match() function of regular expression.'这句字符串的开头,所以这⾥re.match()返回的值为None。
import re
test='Test match() function or regular expression.'
a=re.match(r"function",test)
print(a)
up())
输出
None
re.match 必须从开头匹配
a=re.match(r"function",test)中的r什么意思?意思是“ ”中的是原始字符串,总之在正则表达式中,建议都使⽤原始字符串。
3.2 re.search()
import re
test='Test match() function or regular expression.'
a=re.search(r"function",test)
print(a)
up())
输出:
<re.Match object; span=(13,21), match='function'>
function
re.search⽅法可以匹配字符串中的任意位置的内容。
但是它和re.match()⼀样⼀次只能匹配到⼀个字串内容,⽐如下⾯是某台路由器上show ip int brief的输出结果,我们希望⽤正则表达式来匹配到在该输出内容中出现的所有IPv4地址:
R6#sh ip int br
Interface                  IP-Address      OK? Method Status                Protocol
FastEthernet0/0192.168.1.1    YES manual up                    up
FastEthernet1/0192.168.2.1    YES manual up                    up
FastEthernet2/0192.168.3.1    YES manual up                    up
import re
ip='''R6#sh ip int br
Interface                  IP-Address      OK? Method Status                Protocol
FastEthernet0/0            192.168.1.1    YES manual up                    up
FastEthernet1/0            192.168.2.1    YES manual up                    up
FastEthernet2/0            192.168.3.1    YES manual up                    up
'''#⽤'''可以匹配⼤段字符串
ip_address=re.search(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}",ip)
print(up())
输出:
192.168.1.1
  这⾥我们⽤正则表达式\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}做为模式来匹配任意IPv4地址,注意我们在分割每段IP地址的‘.’前⾯加了转义符号\,如果不加\,写成\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}的话,那么将会匹配到’GigabitEthernet1/1’中的’1/1’.
  print (a.group())后可以看到这⾥我们只匹配到了192.168.1.1这⼀个IPv4地址,如果想匹配到其他所有的IPv4地址,必须⽤到
gr re.findall()。
3.3 re.findall()
  如果字符串中有多个关键词都能被匹配出来,那么可以使⽤re.findall()。与re.match()和re.search()不⼀样的是,re.findall()的返回值是列表,不需要.group()。
import re
ip='''R6#sh ip int br
Interface                  IP-Address      OK? Method Status                Protocol
FastEthernet0/0            192.168.1.1    YES manual up                    up
FastEthernet1/0            192.168.2.1    YES manual up                    up
FastEthernet2/0            192.168.3.1    YES manual up                    up
'''#⽤'''可以匹配⼤段字符串
ip_address=re.findall(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}",ip)
print(type(ip_address))
print(ip_address)
结果:
<class'list'>
['192.168.1.1','192.168.2.1','192.168.3.1']
  这样就匹配到了4个⼈ip地址。
3.4 re.sub()
  re.sub()函数⽤来替换字符串⾥被匹配到的字符串的内容。
R1#sh ip arp
Protocol  Address          Age (min)  Hardware Addr  Type  Interface
Internet  192.168.13.1-  cc01.3ed8.0000  ARPA  FastEthernet0/0
Internet  192.168.13.313  cc03.1048.0000  ARPA  FastEthernet0/0
  以路由器的arp表为例,替换两个mac地址。
import re
mac='''R1#sh ip arp
Protocol  Address          Age (min)  Hardware Addr  Type  Interface
Internet  192.168.13.1            -  cc01.3ed8.0000  ARPA  FastEthernet0/0
Internet  192.168.13.3          13  cc03.1048.0000  ARPA  FastEthernet0/0
'''#⽤'''可以匹配⼤段字符串
mac_address=re.sub(r"\w{4}\.\w{4}\.\w{4}",'1234.abcd.12ab',mac)
print(type(mac_address))
print(mac_address)
结果:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。