Python的正则表达式的模块是re,它的基本语法的规则就是指定一个字符序列,比如:
>>>import re
>>>s='123abc456abce789'
>>>re.findall(r'abc',s) #在s字符串里找到所有的abc,并把他们放到列表list里
以上运行结果就是:['abc','abc']
re规定了若干语法规则:
1)功能字符:'.' '*' '+' '|' '?' '^' '$' '\' 等。
'/': 转义引导符号。
2)规则分界符:'[' ']' '(' ')' '{' '}'等几种特殊括号
3)预定义转义字符集:‘\d’ '\w' '\s'等等,他们是以字符 '\'开头,后面接一个特定的字符形式,用来指示一个预定。
4)其他特殊功能字符:'#' '!' ':' '-' 等,他们只在特定的情况下表示特殊的含义,比如 (?#...) 就表示一个注释,里面的内容会被忽略掉。
1.0 通配符
'.' 匹配1个任意字符(但不包括换行符\n)
'\d' 匹配1个数字,等价于[0-9]
'\D' 是'\d'的反义词,等价于[^0-9]
'\w' 匹配1个字母或数字,等价于 '[a-zA-Z0-9]'
'\W' 是'\w' 的反义词,等价于'[^a-zA-Z0-9]'
'\s' 匹配一个空白符,等价于'[ \t\n\r\v\f](注意含空格);
1.1 '[ ]' 表示集合
1) '-' 用在字母或者数字之间表示一个区间,如下:
'[a-z]' 表示匹配所有的小写英文字母'[A-Z]' 表示匹配所有的大写英文字母
'[a-zA-Z]' 表示匹配所有的大小写英文字母
'[0-9]' 表示匹配0-9的所有数字
ps:'[z-a]' 写法错误,顺序不能颠倒
2)'^' 在开头表示“非”,其他位置则表示他本身,如下:
'[^a-zA-Z]' 表示不匹配所有英文字母
'[a-z^A-Z]' 表示匹配所有英文字母和字符 '^'
3)'|' 表示“或”,将两个规则并列起来,匹配其中之一就可以了,如:
'[a-zA-Z]|[0-9]' 相当于 '[a-zA-Z0-9]' 表示匹配所有的字母和数字
1.2 重复
'*' 0或多次匹配(前面的规则)
'+' 1次或多次匹配 (至少一次,可以多次匹配)>=1
'?' 0或1次匹配 (只匹配前面的规则0次或1次)
例1:匹配以下字符串中的前一部分是字母,后一部分是数字或是没有变量的名字。
>>>s='aaa bbb111 cc22cc 33dd'
>>>re.finall(r'\b[a-z]+\d*\b',s)
['aaa','bbb111']
#匹配至少一个字母开头([a-z]+),以连续数字结尾或没有数字(\d*)
>>>re.findall(r'[a-z]'+\d*',s]
['aaa','bbb111','cc22','cc','dd']
#与上面相比,无'\b'边界,会把单词给拆开
例2:匹配一个数字,这个数字可以是一个整数,也可以是一个科学计数法记录的数字,比如123和10e3都是正确的数字。
>>>s='123 10e3 20e4e4 30ee5'
>>>re.findall(r'\b\d+[eE]?\d*\b',s)
['123','10e3']
#'\b\d+[eE]?\d*\b'拆开来看就是:'\b'前后都有边界 ,开头'\d+' (至少一个数字), 然后'[eE]?' (没有或1个e、E ), 结尾'\d*'(没有或者多个数字);
1.3精确匹配和最小匹配 '{ }'
1.3.1精确匹配规则如下:
'{m}' 精确匹配m次 ,如: '{3}''{m,n}' 匹配最少m次,最多n次 (m
'{m,}' 只匹配最少m次 ,如: '{3,}'
'{,n}' 只匹配最多n次,如: '{,5}'
例:寻找下面的字符串
a:3位数
b:2位数到4位数
c:5位数以上数
d:4位数以下的数
>>>s='1 22 333 4444 55555 666666'
>>>re.findall(r'\b\d{3}\b',s) #a:3位数
['333']
>>>re.findall(r'\b\d{2,4}\b',s) # b:2位数到4位数
['22','333','4444']
>>>re.findall(r'\b\d{5,}\b',s) # c:5位数以上数
['55555','666666']
>>>re.findall(r'\b\d{,4}\b',s) # d:4位数以下的数
['1','22','333','4444']
1.3.2 '*?' '+?' '??' 最小匹配
s=r'/*part1*/code/*part2*/' #此为一个c语言的注释
#如果使用最大规则:
>>>re.findall(r'/\*.*\*/',s)
['/*part1*/code/*part2*/'] #结果把整个字符串都写进去了
>>>re.findall(r'/\*.*?*\*/',s) #'*?'表示尽可能少的匹配
['/*part1*/','/*part2*/']
#ps:'/\*.*?*\*/',其中'/\*'是匹配'*'本身,'.'表示匹配除换行符'\n'外的所有字符,'.*'表示匹配0或多次换行符'\n'外的所有字符,而'.*?'表示匹配尽可能少的匹配0或多次换行符'\n'外的所有字符,就是part1和part2部分。
1.4 其他规则
>>>s='123\n456\n789'
>>>re.findall(r'.+',s) #至少1次('+')匹配除换行符\n外的所有字符
['123','456','789']
>>>re.findall(r'.+',s,re.S) #加上大写的S,则匹配含\n的所有字符
['123\n456\n789']
>>>s='12 34\n56 78\n90'
>>>re.findall(r'^\d+',s,re.M) #至少1次('+')匹配位于行首('^')的数字(\d')
['12','56','90']
>>>re.findall(r'\d+$',s,re.M) #至少1次('+')匹配位于行尾('$')的数字(\d')
['34','78','90']
>>>re.findall(r'\A\d+',s,re.M) #至少1次('+')匹配位于字符串开头('\A')的数字(\d')
['12']
>>>re.findall(r'\d+\Z',s,re.M) #至少1次('+')匹配位于字符串最后('\Z')的数字(\d')
['90']
>>>s='abc abcde bc bcd'
'\b' 匹配单词边界
>>>re.findall(r'\bbc\b',s)
['bc'] #匹配一个独立的单词'bc',而当它是其他单词的一部分的时候,不匹配
'\B' 匹配非边界
>>>re.findall(r'\Bbc\W+',s) #匹配包含'bc'但不以‘bc’开头,并且后面至少有一个字母或数字的单词
['bcde'] #成功匹配了'abcde'中的'bcde',而没有匹配'bcd'
>>>re.findall(r'\sbc\s',s) #匹配一个独立的单词bc
[' bc '] #不过输出的bc前后会有空格
'(?:)' 无捕获组
例:匹配字符串中重复的'ab'
>>>s='ababab abbabb aabaab'
>>>re.findall(r'\b(?:ab)+\b',s)
['ababab']
>>>re.findall(r'\b(ab)+\b',s) #只用一个括号,就相当于一个组(grou)
['ab'] #ps:关于组后面会详细介绍
'(?#)' 注释
python允许你在正则表达式中注释,在'(?#'和')'中的内容将会被忽略
2.界定
'(?<=...)' 前向界定
'(?=...)' 后向界定
ps:括号中的'...'代表你希望匹配的字符串的前面、后面应该出现的字符串
例:你希望找出C语言注释中的内容,他们是否包含在'/*'和'*/'之间,不过你并不希望匹配的结果把'/*'和'*/'也包括进来,那么你可以这样用。
>>>s=r'/*comment1*/code/*comment2*/'
>>>re.findall(r'(?<=/\*).+?(?=\*/)',s) #匹配字符前面是'/*'后面是'*/'的字符
['comment1','comment2']
ps:前向界定的表达式必须是常值,不过可以在后向界定写正则,如下所示:
>>>s='aaa111aaa,bbb222,333ccc'
>>>re.findall(r'(?<=[a-z]+)\d+(?=[a-z]+)',s) #此用法错误,前向界定里不能用正则
error:look-behind requires fixed-width pattern. #结果报错了
>>>re.findall(r'\d+(?=[a-z]+)',s) #后面的界定可以用正则
['111','333'] #界定是包含在结果中的
ps:如果你一定要匹配夹在字母中间的数字,你可以使用组(group)的方式,如:
>>>re.findall(r'[a-z]+(\d+)[a-z]+',s) #规则内,组以外的会被忽略
['111']
'(?#只有当你希望的字符串前面不是'...'的内容才匹配
'(?!...)' 后向非界定 #只有当你希望的字符串后不跟着'...'的内容才匹配
s='aaa111aaa,bbb222,333ccc'
>>>re.findall(r'\d+(?![a-z]+)',s)
['11','222','333']
>>>re.findall(r'\d+(?!\w+)',s) #匹配数字后面不跟着字母或者数字
['222']
3.组的基本知识
1) '(' ')' 无命名组
>>>s='aaa111aaa,bbb222,333ccc'
>>>re.findall(r'[a-z]+(\d+)[a-z]+',s) #一个组
['111'] #只返回了匹配包含在'( )'里的
>>>s='aaa111aaa,bbb222,333ccc,444ddd444,555eee666,fff777ggg'
>>>re.findall(r'([a-z]+)\d+([a-z)+',s) #有两个组,找出中间夹有数字的字母
[('aaa','aaa'),('fff','ggg')]
>>>re.findall(r'[a-z]+(/d+)([a-z]+)',s)
[('111','aaa'),('777','ggg')] #有组的话,组以外的不返回
2) '(?p=name)'调用已匹配的命名组
ps:就是组命名,然后下次要使用相同的规则的组时候可以直接调用,如
>>>re.findall(r'(?p
[a-z]+) \d(?p=gl)' #找出被中间夹有数字的前后同样的字母['aaa']
3)'\number' 通号调用已匹配的组
>>>re.findall(r'([a-z]+)\d+\1',s) #找出被中间夹有数字的前后同样的字母
['aaa']
>>>s='111aaa222aaa111,333bbb444bb33'
>>>re.findall(r'(\d+)([a-z]+)(\d+)(\2)(\1)',s) #找出完全对称的‘数字-字母-数字-字母-数字’
[('111','aaa','222','aaa','111')] #注意'\number'与'(\number)'的区别,以及命名组调用的区别
4)'(?(id/name)yes-pattern}|no-pattern)' 判断指定组是否已匹配,执行相应的规则
>>>s='< usr1@mail1 > ursl2@mail2'
>>>re.findall(r'(<)?\s*(\w+@\w+)\s*(?(1)>)',s)
[('<','usr1@mail1'),('','ursl2@mail2')]