Python re正则表达式

Posted by ZhangShun Blog on January 7, 2019

re re模块下的函数 —

compile

re.compile(pattern[, flags])

作用:把正则表达式语法转化成正则表达式对象

flags定义包括:

re.I:忽略大小写

re.L:表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境

re.M:多行模式

re.S:’.’并且包括换行符在内的任意字符(注意:’ . ’不包括换行符)

re.U: 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库

用了re.compile以后,正则对象会得到保留,这样在需要多次运用这个正则对象的时候,效率会有较大的提升.

re.search(pattern, string[, flags])

search (string[, pos[, endpos]])

作用:在字符串中查找匹配正则表达式模式的位置,返回 MatchObject 的实例,如果没有找到匹配的位置,则返回 None

match

re.match(pattern, string[, flags])

match(string[, pos[, endpos]])

作用:match() 函数只在字符串的开始位置尝试匹配正则表达式,也就是只报告从位置 0 开始的匹配情况,而 search() 函数是扫描整个字符串来查找匹配。如果想要搜索整个字符串来寻找匹配,应当用 search()。

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python
import re
r1 = re.compile(r'world')
if r1.match('helloworld'):
    print('match succeeds')
else:
    print('match fails')
if r1.search('helloworld'):
    print('search succeeds')
else:
    print('search fails')

说明一下:r是raw(原始)的意思。因为在表示字符串中有一些转义符,如表示回车’\n’。如果要表示\需要写为’\‘。但如果我就是需要表示一个’'+’n’,不用r方式要写为:’\n’。但使用r方式则为r’\n’这样清晰多了

split

re.split(pattern, string[, maxsplit=0, flags=0])

split(string[, maxsplit=0])

作用:可以将字符串匹配正则表达式的部分割开并返回一个列表

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
#简单IP分析
import re
r1 = re.compile(r'\W+')
print(r1.split(r'192.168.1.1'))
print(re.split(r'(\W+)','192.168.1.1'))
print(re.split(r'(\W+)','192.168.1.1',1))

#输出结果为:
['192', '168', '1', '1']
['192', '.', '168', '.', '1', '.', '1']
['192', '.', '168.1.1']

findall

re.findall(pattern, string[, flags])

findall(string[, pos[, endpos]])

作用:在字符串中找到正则表达式所匹配的所有子串,并组成一个列表返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
#查找[]包括的内容(贪婪和非贪婪查找)
import re
r1 = re.compile(r'([.*])')
print(re.findall(r1,"hello[hi]heldfsdsf[iwonder]lo"))
r1 = re.compile(r'([.*?])')
print(re.findall(r1,"hello[hi]heldfsdsf[iwonder]lo"))
print(re.findall(r'[0-9]{2}',"fdskfj1323jfkdj"))
print(re.findall('([0-9][a-z])',"fdskfj1323jfkdj"))
print(re.findall(r'(?=www)',"afdsfwwwfkdjfsdfsdwww"))
print(re.findall(r'(?<=www)',"afdsfwwwfkdjfsdfsdwww"))


#输入结果:
[]
[]
['13', '23']
['3j']
['', '']
['', '']

finditer

re.finditer(pattern, string[, flags])

finditer(string[, pos[, endpos]])

说明:和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并组成一个迭代器返回。

1
2
3
4
5
>>> for m in re.finditer('\w+', 'hello, world!'):
...     print(m.group())
...
hello
world

sub

re.sub(pattern, repl, string[, count, flags])

sub(repl, string[, count=0])

说明:在字符串 string 中找到匹配正则表达式 pattern 的所有子串,用另一个字符串 repl 进行替换。如果没有找到匹配 pattern 的串,则返回未被修改的 string。Repl 既可以是字符串也可以是一个函数。

1
2
3
4
5
6
7
#!/usr/bin/env python
import re
p = re.compile('(one|two|three)')
print(p.sub('num','one word two words three words apple',2))
 
#输出结果:
num word num words three words apple

escape

把string中,除了字母和数字以外的字符,都加上反斜杆。

1
2
>>> print(re.escape('abc123_@#$'))
abc123_\@\#\$

函数的方法

group([group1, …])

返回一个或多个子组。如果参数为一个,就返回一个子串;如果参数有多个,就返回多个子串注册的元组。如果不传任何参数,效果和传入一个0一样,将返回整个匹配。如果某个groupN未匹配到,相应位置会返回None。如果某个groupN是负数或者大于group的总数,则会抛出IndexError异常

1
2
3
4
5
6
7
8
9
>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0) #整个匹配
'Isaac Newton'
>>> m.group(1)#第一个子串
'Isaac'
>>> m.group(2)#第二个子串
'Newton'
>>> m.group(1,2) #多个子串组成元组
('Isaac', 'Newton')

groups([default])

返回一个由所有匹配到的子串组成的元组。default参数,用于给那些没有匹配到的组做默认值,它的默认值是None

1
2
3
4
5
6
7
8
9
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')
#default的作用
>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups() #第二个默认是None
('24', None)
>>> m.groups('0')#现在默认变成0
('24', '0')

groupdict([default])

返回一个包含所有命名组的名字和子串的字典,default参数,用于给那些没有匹配到的组做默认值,它的默认值是None

1
2
3
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.groupdict()
{'first_name': 'Malcolm', 'last_name': 'Reynolds'}

start([group]),end([group])

给定组匹配项的开始位置 or 给定组匹配项的结束位置

1
2
3
4
5
6
>>>pat = re.compile(r'www\.(.*)\.(.*)')       #用()表示1个组,2个组
>>>m = pat.match('www.dxy.com')
>>>print(m.start(2))
8
>>>print(m.end(2))
11

span([group])

返回一个元组: (m.start(group), m.end(group))

pos

就是传给RE对象的search()或match()方法的参数pos,代表RE开始搜索字符串的位置

特殊字符 意义说明
. 匹配包括换行符以内的任意一个字符。点号,在普通模式,它匹配除换行符外的任意一个字符。
^ 匹配一个字符串的开始,在 MULTILINE 模式下,也将匹配任意一个新行的开始。
$ 匹配一个字符串的结尾或者字符串最后面的换行符,在 MULTILINE 模式下,也匹配任意一行的行尾。
* 匹配*前面re的重复0次或者任意多次,而且总是试图尽量多次地匹配。
+ 匹配+前面re的重复1次或者无限次,如果有的话,也尽量匹配1次。
? 匹配?前面re的重复0次或者1次,如果有的话,也尽量匹配1次。
*?, +?, ?? 可以看到’*‘,’+’和’?’都是贪婪的,但这也许并不是我们说要的,所以,可以在后面加个问号,将策略改为非贪婪,只匹配尽量少的RE,也就是第一个匹配结果。
{m} m是一个数字,匹配{m}前面的re重复m次。
{m,n} m和n都是数字,匹配{m,n}前面的RE重复m到n次,例如a{3,5}匹配3到5个连续的a。注意,如果省略m,将匹配0到n个前面的RE;如果省略n,将匹配n到无穷多个前面的RE。
{m,n}? {m,n},也是贪婪的,这个也可以通过加问号改变。a{3,5}?如果可能的话,将只匹配3个a。
\ 反斜杆,转义’*‘,’?’等特殊字符,或者指定一个特殊序列,强烈建议用raw字符串来表述正则。
[] 方括号,用于指定一个字符的集合。可以单独列出字符,也可以用’-‘连接起止字符以表示一个范围。特殊字符在中括号里将失效,比如[akm$]就表示字符’a’,’k’,’m’,或’$’,在这里$也变身为普通字符了。[a-z]匹配任意一个小写字母,[a-zA-Z0-9]匹配任意一个字母或数字。还可以对一个字符集合取反,以匹配任意不在这个字符集合里的字符,取反操作用一个’^’放在集合的最前面表示,放在其他地方的’^’将不会起特殊作用。例如[^5]将匹配任意不是’5’的字符;[^^]将匹配任意不是’^’的字符。注意:在中括号里+、*、(、)这类字符将会失去特殊含义,仅作为普通字符。反向引用也不能在中括号内使用。
(...) 分组匹配,从左到右,每遇到一个 ( 编号+1,分组后面可加数量词 )
(?...) 这是一个表达式的扩展符号。’?’后的第一个字母决定了整个表达式的语法和含义,除了(?P…)以外,表达式不会产生一个新的组。(?iLmsux)表示’i’、’L’、’m’、’s’、’u’、’x’里的一个或多个字母。表达式不匹配任何字符,但是指定相应的标志:re.I(忽略大小写)、re.L(依赖locale)、re.M(多行模式)、re.S(.匹配所有字符)、re.U(依赖Unicode)、re.X(详细模式)。关于各个模式的区别。使用这个语法可以代替在re.compile()的时候或者调用的时候指定flag参数。另外,还要注意(?x)标志如果有的话,要放在最前面。
(?:...) 匹配内部的RE所匹配的内容,但是不建立组。
(?P<name>...) 和普通的圆括号类似,但是子串匹配到的内容将可以用命名的name参数来提取。组的name必须是有效的python标识符,而且在本表达式内不重名。命名了的组和普通组一样,也用数字来提取,也就是说名字只是个额外的属性。
(?#...) 注释,圆括号里的内容会被忽略。
(?=...) 如果 … 匹配接下来的字符,才算匹配,但是并不会消耗任何被匹配的字符。例如 Isaac (?=Asimov) 只会匹配后面跟着 ‘Asimov’ 的 ‘Isaac ‘,这个叫做“前瞻断言”。
(?!...) 和(?=…)相反,只匹配接下来的字符串不匹配 … 的串,这叫做“反前瞻断言”。
(?<=...) 只有当当前位置之前的字符串匹配 … ,整个匹配才有效,这叫“后顾断言”。字符串’abcdef’可以匹配正则(?<=abc)def,因为会后向查找3个字符,看是否为abc。所以内置的子RE,需要是固定长度的,比如可以是abc、a|b,但不能是a*、a{3,4}。注意这种RE永远不会匹配到字符串的开头。
(?<!...) 这个叫做“反后顾断言”,子RE需要固定长度的,含义是前面的字符串不匹配 … 整个才算匹配。
(?(id/name)yes-pattern|no-pattern) 如有由id或者name指定的组存在的话,将会匹配yes-pattern,否则将会匹配no-pattern,通常情况下no-pattern也可以省略。例如:(<)?(\w+@\w+(?:.\w+)+)(?(1)>)可以匹配 ‘user@host.com’ 和 ‘user@host.com’,但是不会匹配 ‘<user@host.com’。
特殊序列符号 意义说明
. 通配符,除换行符外的任意的1个字符
\d 相当于[0-9]
\D 非数字
\s 匹配任何空白字符,等效于[ \t\n\r\f\v]
\S 和\s相反,匹配任意非空白字符:[^\t\n\r\r\v]
\w 匹配任意数字和字母:[a-zA-Z0-9]
\W 和\w相反,匹配任意非数字和字母:[^a-zA-Z0-9]
\A 只匹配字符串的开始
\Z 只匹配字符串的结尾

1、匹配一段文本中的每行的邮箱

1
2
3
4
y='123@qq.comaaa@163.combbb@126.comasdfasfs33333@adfcom'
import re
ret=re.findall('\w+@(?:qq|163|126).com',y)
print(ret)

2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’

1
2
3
4
5
6
time='asfasf1990-07-12asdfAAAbbbb434241'
import re
ret=re.search(r'(?P<year>19[09]\d)-(?P<month>\d+)-(?P<days>\d+)',time)
print(ret.group('year'))
print(ret.group('month'))
print(ret.group('days'))