python 正则表达式
re 模块
分析日志,提取信息
普通字符
原字符:
. 代表任意一个字符
^ 以什么开头 , ^[abc]表示以abc开头
$ 以什么结尾
* 匹配前面的字符或表达式0次或多次 0,1,2 ……
+ 匹配前面字符或表达式至少1次 1,2,3 ……
? 匹配前面字符或表达式0次或1次 0,1
{} 里面可以是数值,{123}作为一个整体,可以匹配该整体几次
[] 匹配里面的某个字符,里面可以是个集合[0-9,a-z]
\ 转意,\$,表示就是 $
| 表示或
() 表示分组
正则表达式
\d 匹配任何十进制数,相当于[0-9]
\D 匹配任何非十进制数,相当于[^0-9]
\s 匹配任何空白字符,相当于[\t\n\r\f\v]
\S 匹配任何非空白字符,相当于[^\t\n\r\f\v]
\w 匹配任何字母和数字,相当于[a-zA-Z0-9]
\W 匹配任何非字母数字字符,相当于[^a-zA-Z0-9]
pattern:正则表达式,string:字符串 flag:标记,默认是0,返回的是一个列表
In [1]: import re
In [2]: help(re.findall)
Help on function findall in module re:
findall(pattern, string, flags=0)
Return a list of all non-overlapping matches in the string.
If one or more groups are present in the pattern, return a
list of groups; this will be a list of tuples if the pattern
has more than one group.
In [1]: import re
In [2]: help(re.findall)
#匹配以ab开头的行,没有找到
In [3]: re.findall(r'^ab+', 'asdabbbb')
Out[3]: []
#匹配包含ab,b可以有多个,匹配到abbbb
In [4]: re.findall(r'ab+', 'asdabbbb')
Out[4]: ['abbbb']
#匹配以ab开头的字符,ab
In [5]: re.findall(r'^ab+', 'absdabbbb')
Out[5]: ['ab']
#匹配包含字符ab,匹配结果ab,abbbb
In [6]: re.findall(r'ab+', 'absdabbbb')
Out[6]: ['ab', 'abbbb']
# .表示匹配任意一个字符
In [7]: re.findall(r".",'abc\nab\n')
Out[7]: ['a', 'b', 'c', 'a', 'b']
# re.S表示“.”匹配任意一个字符,包括换行符
In [8]: re.findall(r".",'abc\nab\n',re.S)
Out[8]: ['a', 'b', 'c', '\n', 'a', 'b', '\n']
# abc$表示以abc结尾的字符
In [10]: re.findall(r'abc$','12345abc')
Out[10]: ['abc']
# ab*表示:b是0次或多次,匹配ab或a或abbbb 个数b>=0 ab* = ab{0,} *0次或多次
In [17]: re.findall(r'ab*','abcea')
Out[17]: ['ab', 'a']
In [22]: re.findall(r'ab*','abceabbbba')
Out[22]: ['ab', 'abbbb', 'a']
# ab+表示:b是1次或多次,匹配ab或则abbbb 个数b>=1 ab+ = ab{1,} +1次或多次
In [18]: re.findall(r'ab+','abcea')
Out[18]: ['ab']
In [19]: re.findall(r'ab+','abceabbbb')
Out[19]: ['ab', 'abbbb']
# ab?表示:b是0次或1次,匹配ab或则a 个数b=0或=1 ab? = ab{0,1} ?0次或1次
In [20]: re.findall(r'ab?','abceabbbba')
Out[20]: ['ab', 'ab', 'a']
# ab{0,}=ab+表示: b是0次或多次, 个数b>=0
In [29]: re.findall(r'ab{0,}','abceabbbbcdefabbbbbbbbbbbbbbbbbbbb')
Out[29]: ['ab', 'abbbb', 'abbbbbbbbbbbbbbbbbbbb']
# ab{0,}表示: b是0-10次, 个数b 0<=b<=10
In [30]: re.findall(r'ab{0,10}','abceabbbbcdefabbbbbbbbbbbbbbbbbbbb')
Out[30]: ['ab', 'abbbb', 'abbbbbbbbbb']
# ab{0,}表示: b是0-1次, 个数b 0<=b<=1
In [32]: re.findall(r'ab{0,1}','abceabbbbcdefa')
Out[32]: ['ab', 'ab', 'a']
#\d表示一个数字,匹配1,2,3,0
In [38]: re.findall(r'[\d]','abcea1230')
Out[38]: ['1', '2', '3', '0']
#\d表示一个字符,a-z表示任何一个小写字母,表示a-z任意一个字符
In [33]: re.findall(r'[\da-z]','abcea')
Out[33]: ['a', 'b', 'c', 'e', 'a']
#\d表示一个字符,表示a-z任意一个字符任意数字
In [34]: re.findall(r'[\da-z]','abcea123')
Out[34]: ['a', 'b', 'c', 'e', 'a', '1', '2', '3']
#\d表示一个字符,表示a-z任意一个小写字母,+表示[\da-z]是一个整体,出现一次或多次
In [35]: re.findall(r'[\da-z]+','abcea123')
Out[35]: ['abcea123']
#\转译字符,\$表示美元符号$,而不是以abc结尾
In [40]: re.findall(r'abc$' , 'abc$')
Out[40]: []
In [41]: re.findall(r'abc\$' , 'abc$')
Out[41]: ['abc$']
#|表示或,包含a或b
In [45]: re.findall(r'a|b','abc')
Out[45]: ['a', 'b']
#不包含A或B
In [46]: re.findall(r'a|b','AB')
Out[46]: []
#使用re.I表示忽略大小写
In [48]: re.findall(r'a|b','AB',re.I)
Out[48]: ['A', 'B']
#\w表示匹配任意字母或数字,返回一个列表,()小括号表示分组,2个(\w+)表示匹配2个单词
In [52]: re.findall(r'(\w+) (\w+)', 'hello world')
Out[52]: [('hello', 'world')]
#\w表示匹配任意字母或数字,返回一个列表,()小括号表示分组,打印分组中的内容,2个(\w+)表示匹配2个单词
In [58]: re.findall(r'(\w+) abc (\w+)', 'hello abc world')
Out[58]: [('hello', 'world')]
一些方法
re.match() 方法:从左到右,返回一个对象,只匹配开始的位置
re.search() 方法:扫描字符串,找到这个re匹配的位置
re.match()和re.search()区别:
re.match只匹配字符串的开始,如果字符串不符合正则表达式,则匹配失败,函数返回none,
re.search匹配整个字符串,直到找到一个匹配,如果成功的话,返回MatchObject实例,例如,找到hello,返回hello
re.sub():替换
re.match() 方法:从左到右,返回一个对象,只匹配开始的位置,虽然包含hello,但是不在开头,所以匹配结果胃null
In [19]: m = re.match(r'(hello)\s', 'ab hello world')
In [20]: m
In [21]: help(re.match)
Help on function match in module re:
match(pattern, string, flags=0)
Try to apply the pattern at the start of the string, returning
a match object, or None if no match was found.
#\w表示匹配任意数字和字母[a-zA-Z0-9],\s表示匹配任意空白字符:[\t\n\r\f\v]
In [24]: m = re.match(r'(\w)+\s', 'ab hello world')
In [25]: m
Out[25]: <_sre.SRE_Match at 0x7f2a186ebaf8>
In [26]: m.group()
Out[26]: 'ab ' #匹配结果是ab和空格
re.search() 方法:扫描字符串,找到这个re匹配的位置,匹配整行,即使不在开头位置
In [30]: s = re.search(r'hello', 'ab hello world')
In [31]: s
Out[31]: <_sre.SRE_Match at 0x7f2a1b30e7e8>
In [32]: s.group()
Out[32]: 'hello'
#\s 表示匹配hello后边的空格
In [33]: s = re.search(r'hello\s', 'ab hello world')
In [34]: s.group()
Out[34]: 'hello '
re.sub():替换 从string找pattern,用repl替换,count 替换几次
In [60]: help(re.sub)
Help on function sub in module re:
sub(pattern, repl, string, count=0, flags=0)
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the match object and must return
a replacement string to be used.
#查找hellohe,使用HE替换he,默认都替换
In [68]: re.sub(r'he','HE','hellohe')
Out[68]: 'HElloHE'
#count=0表示都替换
In [69]: re.sub(r'he','HE','hellohe',count=0)
Out[69]: 'HElloHE'
#count=2表示使用HE替换he2次
In [70]: re.sub(r'he','HE','hellohe',count=2)
Out[70]: 'HElloHE'
#count=1表示使用HE替换he1次
In [71]: re.sub(r'he','HE','hellohe',count=1)
Out[71]: 'HEllohe'
正则表达式
compile()将正则表达式编译成对象,并用她们来进行配置
In [72]: import re
In [73]: p = re.compile('ab*') # *表示b出现0次或多次
In [74]: p
Out[74]: re.compile(r'ab*')
In [75]: s = 'abc'
In [76]: p.findall(s)
Out[76]: ['ab']
In [89]: p.findall('abbbbb')
Out[89]: ['abbbbb']
In [79]: type(p)
Out[79]: _sre.SRE_Pattern
In [80]: p.
p.findall p.groupindex p.pattern p.split
p.finditer p.groups p.scanner p.sub
p.flags p.match p.search p.subn
In [81]: p.findall('a')
Out[81]: ['a']
In [82]: p.findall('abcde')
Out[82]: ['ab']
In [83]: p.search('tj abc abd')
Out[83]: <_sre.SRE_Match at 0x7f2a1200ab28>
In [84]: s = p.search('tj abc abd')
In [85]: s.group()
Out[85]: 'ab'
In [90]: s = p.match('a bcdef')
In [91]: s.group()
Out[91]: 'a'
In [92]: s = p.match('abbbb bcdef')
In [93]: s.group()
Out[93]: 'abbbb'
In [77]: reg = r'ab*'
In [78]: re.findall(reg,s)
Out[78]: ['ab']
re.I : 不区分大小写
re.S: 使 " . " 匹配包括换行符在内的所有字符
例如:
In [104]: p = re.compile(r'G.d')
In [107]: p.findall('god')
Out[107]: []
In [108]: p.findall('God')
Out[108]: ['God']
In [111]: p = re.compile(r'G.d',re.I)
In [112]: p
Out[112]: re.compile(r'G.d', re.IGNORECASE)
In [113]: p.findall('god')
Out[113]: ['god']
In [114]: p.findall('God')
Out[114]: ['God']
In [115]: p = re.compile(r'G.d',re.I|re.S)
In [116]: p.findall('g\nd')
Out[116]: ['g\nd']
In [117]: p.findall('g\nD')
Out[117]: ['g\nD']
In [118]: p.findall('g\tD')
Out[118]: ['g\tD']
re.M:多行匹配
.代表任意一个字符foo.匹配了foo2,$表示以foo.结尾
In [7]: re.findall(r'foo.$', 'foo1\nfoo2\n')
Out[7]: ['foo2']
re.M表示\n为换行,除了foo2,foo1也匹配成功
In [8]: re.findall(r'foo.$', 'foo1\nfoo2\n',re.M)
Out[8]: ['foo1', 'foo2']
In [9]: re.findall(r'foo.$', 'foo1\nfoo2\n',re.MULTILINE)
Out[9]: ['foo1', 'foo2']
In [18]: data = open('/etc/passwd').read()
In [19]: p=re.compile(r'^ftp', re.M)
In [20]: p.findall(data)
Out[20]: ['ftp']
In [21]: p.search(data)
Out[21]: <_sre.SRE_Match at 0x7f3e657f5988>
In [22]: p.search(data).group()
Out[22]: 'ftp'
In [24]: data
Out[24]: 'root:x:0:0:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nadm:x:3:4:adm:/var/adm:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/spool/mail:/sbin/nologin\nuucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin\noperator:x:11:0:operator:/root:/sbin/nologin\ngames:x:12:100:games:/usr/games:/sbin/nologin\ngopher:x:13:30:gopher:/var/gopher:/sbin/nologin\nftp:x:14:50:FTP User:/var/ftp:/sbin/nologin\nnobody:x:99:99:Nobody:/:/sbin/nologin\ndbus:x:81:81:System message bus:/:/sbin/nologin\nvcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin\nsaslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin\npostfix:x:89:89::/var/spool/postfix:/sbin/nologin\nsshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin\nrpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin\nrpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin\nnfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin\nradvd:x:75:75:radvd user:/:/sbin/nologin\nhaldaemon:x:68:68:HAL daemon:/:/sbin/nologin\nqemu:x:107:107:qemu user:/:/sbin/nologin\ndaixuan:x:500:500::/home/daixuan:/bin/bash\nmysql:x:501:501::/home/mysql:/sbin/nogin\nzabbix:x:498:497:Zabbix Monitoring System:/var/lib/zabbix:/sbin/nologin\nnagios:x:497:496::/var/spool/nagios:/sbin/nologin\nntp:x:38:38::/etc/ntp:/sbin/nologin\nnrpe:x:496:495:NRPE user for the NRPE service:/var/run/nrpe:/sbin/nologin\napache:x:48:48:Apache:/var/www:/sbin/nologin\nnginx:x:495:494:Nginx web server:/var/lib/nginx:/sbin/nologin\nmysql-proxy:x:494:493:MySQL-Proxy user:/:/sbin/nologin\nmailnull:x:47:47::/var/spool/mqueue:/sbin/nologin\nsmmsp:x:51:51::/var/spool/mqueue:/sbin/nologin\namos:x:502:502::/home/amos:/bin/bash\ncarbon:x:493:492:Carbon cache daemon:/var/lib/carbon:/sbin/nologin\nsquid:x:23:23::/var/spool/squid:/sbin/nologin\ndockerroot:x:492:491:Docker User:/var/lib/docker:/sbin/nologin\ngit:x:503:503::/home/git:/usr/bin/git-shell\nmemcached:x:491:490:Memcached daemon:/var/run/memcached:/sbin/nologin\ndaixuan123:x:504:504::/home/daixuan123:/bin/bash\nuser1:x:505:505::/home/user1:/bin/bash\n'
编译标志flags,re.X正则可以用多行来写
邮箱为例子
In [30]: rmail = r'[\w_-]+@[\w]+\.[a-zA-Z]{2,3}'
In [31]: smail = 'root@123.com'
In [32]: re.findall(rmail,smail)
Out[32]: ['root@123.com']
In [33]: re.findall(rmail,'david-dai@zamplus.com')
Out[33]: ['david-dai@zamplus.com']
#定义rmail使用多行来写,匹配时候使用re.X支持多行
In [34]: rmail = r"""[\w_-]+
...: @
...: [\w]+
...: \.
...: [a-z]{2,3}"""
In [35]: re.findall(rmail,smail)
Out[35]: []
In [36]: re.findall(rmail,smail, re.X)
Out[36]: ['root@123.com']
In [37]: re.findall(rmail, 'david-dai@zamplus.com', re.X)
Out[37]: ['david-dai@zamplus.com']
In [38]: re.findall(rmail, 'david-dai@zamplus.com')
Out[38]: []
注:
[...]中括号是匹配里面的某一个字符。
[...]+表示至少匹配中括号里某一个字符。
其实[\w_]+ 和 [\w]+效果是一样,\w里多包括'_'这个字符
greedy模式 ?阻止贪婪模式,默认是贪婪匹配,带问号的是最短匹配。只匹配标签:<h1> </h1>
In [4]: ss = '<h1> hello world </h1>'
In [5]: re.findall(r'<.*>', ss)
Out[5]: ['<h1> hello world </h1>']
In [6]: re.findall(r'<.*?>', ss)
Out[6]: ['<h1>', '</h1>']
#匹配/var/log/messages
In [37]: reg_syslog = re.compile(r'\w+ \d+ [\d:]+ [\w\.]+ \w+(\[\d+\])?: .*')
In [38]: ss = 'Dec 28 07:47:53 daixuan auditd[1476]: Audit daemon rotating log files'
In [39]: s = reg_syslog.search(ss).group()
In [40]: s
Out[40]: 'Dec 28 07:47:53 daixuan auditd[1476]: Audit daemon rotating log files'
正则匹配的分组表达 (?P<name> \w+)
In [55]: ss = 'Dec 28 07:47:53 daixuan auditd[1476]: Audit daemon rotating log files'
In [56]: reg_syslog = re.compile(r'(?P<logtime>\w+ \d+ [\d:]+) (?P<hostname>[\w\.]+) (?P<program>\w+(\[\d+\])?:) (?P<messages>.*)')
...:
In [57]: s = reg_syslog.search(ss)
In [58]: sg = reg_syslog.search(ss).group()
In [59]: sg
Out[59]: 'Dec 28 07:47:53 daixuan auditd[1476]: Audit daemon rotating log files'
#得到字典
In [62]: s.groupdict()
Out[62]:
{'hostname': 'daixuan',
'logtime': 'Dec 28 07:47:53',
'messages': 'Audit daemon rotating log files',
'program': 'auditd[1476]:'}
#得到与元祖
In [63]: s.groups()
Out[63]:
('Dec 28 07:47:53',
'daixuan',
'auditd[1476]:',
'[1476]',
'Audit daemon rotating log files')
#每条日志间的空格也考虑进去了
In [64]: reg_syslog = re.compile(r'(?P<logtime>\w+\s+\d+\s[\d:]+)\s(?P<hostname>[\w\.]+)\s(?P<program>\w+(\[\d+\])?:) (?P<messages>.*)')
In [65]: ss = 'Dec 28 07:47:53 daixuan auditd[1476]: Audit daemon rotating log files'
In [66]: sg = reg_syslog.search(ss).group()
In [67]: s.groupdict()
Out[67]:
{'hostname': 'daixuan',
'logtime': 'Dec 28 07:47:53',
'messages': 'Audit daemon rotating log files',
'program': 'auditd[1476]:'}
In [68]: s.groups()
Out[68]:
('Dec 28 07:47:53',
'daixuan',
'auditd[1476]:',
'[1476]',
'Audit daemon rotating log files')
使用正则表达式获取IP,非常放方便实用
[root@133 systeminformation]# vim re_ip.py
#!/usr/bin/env python
import re
from subprocess import Popen,PIPE
def getIfconfig():
tuple_addr = ('lo','vir','vnet','em3','em4')
p = Popen(['ifconfig'], stdout=PIPE)
data = p.stdout.read().split('\n\n')
return [i for i in data if i and not i.startswith(tuple_addr)]
def parseIfconfig(data):
re_devname = re.compile(r'(br|em|docker)[\d:]+', re.M)
re_mac = re.compile(r'HWaddr ([0-9A-F:]{17})', re.M)
re_ip = re.compile(r'(inet addr):([\d\.]{7,15})', re.M) #正则匹配(),group(1)代表匹配:(inet addr),group(2)代表匹配:([\d\.]{7,15})
print re_ip.search(data).group(2)
devname = re_devname.search(data)
if devname:
devname = devname.group()
else:
devname = ''
mac = re_mac.search(data)
if mac:
mac = mac.group(1)
else:
mac = ''
ip = re_ip.search(data)
if ip:
ip = ip.group(2) #打印IP地址
else:
ip = ''
return {devname: [ip, mac]}
if __name__ == '__main__':
dic = {}
data = getIfconfig()
for i in data:
dic.update(parseIfconfig(i))
print dic
[root@133 systeminformation]# python re_ip.py
112.65.140.133
172.17.42.1
192.168.101.237
{'docker0': ['172.17.42.1', '00:00:00:00:00:00'], 'br1': ['112.65.140.133', 'A4:BA:DB:20:93:23'], 'em2': ['192.168.101.237', 'A4:BA:DB:20:93:25']}
不是很明白这的group分组,数字怎么分的,以什么为分隔点
#按照括号分的,第一个括号是group(1),第二括号是group(2),以此类推。
#group(0)与group()相同,表示匹配到的内容。
In [35]: m = re.match(r'(\w+)\s(\w+)\s', 'hello world abc')
In [36]: m.group()
Out[36]: 'hello world '
In [37]: m.group(0)
Out[37]: 'hello world '
In [38]: m.group(1)
Out[38]: 'hello'
In [39]: m.group(2)
Out[39]: 'world'
转载于:https://blog.51cto.com/daixuan/1887003