Py002-02-11正则re

re模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import re

str = '''
张三 20 广州 173 50 13613133344
张四 30 深州 173 50 13813133344
张五 25 天津 173 50 15613133366
张六 13 北京 173 50 13613133388
张七 44 宁波 173 50 18213133377
张八 33 浙江 173 50 13013133341
张九 90 杭州 173 50 13813133312
张二 10 山西 173 50 13913133315
张一 22 大同 173 50 05713133344
'''

# 查找手机号

# 只找到第一个
print(re.search("[0-9]{11}",str))

# 查找所有匹配的手机号
print(re.findall("1[1-9]{10}",str))

常用正则规则

正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾, 若指定flags MULTILINE ,re.search('foo.$','foo1\nfoo2\n',re.MULTILINE).group() 会匹配到foo1
'*' 匹配*号前的字符0次或多次, re.search('a*','aaaabac') 结果'aaaa'
'+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次 ,re.search('b?','alex').group() 匹配b 0次
'{m}' 匹配前一个字符m次 ,re.search('b{3}','alexbbbs').group() 匹配到'bbb'
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配, re.search("(abc){2}a(123|45)", "abcabca456c").group() 结果为'abcabca45'


'\A' 只从字符开头匹配同(^),re.search("\Aabc","alexabc") 是匹配不到的,相当于re.match('abc',"alexabc") 或^
'\Z' 匹配字符结尾,同$
'\d' 匹配数字0-9
'\D' 匹配非数字
'\w' 匹配[A-Za-z0-9]
'\W' 匹配非[A-Za-z0-9]
'\s' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'

'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}

re的匹配语法有以下几种

  • re.match 从头开始匹配
  • re.search 匹配包含
  • re.findall 把所有匹配到的字符放到以列表中的元素返回
  • re.split 以匹配到的字符当做列表分隔符
  • re.sub 匹配字符并替换
  • re.fullmatch 全部匹配

match

1
2
3
4
5
6
7
8
9
10
# 从头匹配
a = re.match('[0-9]','abcde2') # None
b = re.match('[0-9]','1abcd2') # <_sre.SRE_Match object; span=(0, 1), match='1'>
c = re.match('[0-9]','ab3cd2') # None


# 如何取到匹配返回的值呢?
# 因为返回值可能是None 所以要做判断
if b:
print(b.group())

search

1
2
3
4
5
6
7
8
9
# 全局匹配
a = re.search('[0-9]','abcdef') # [] ['1'] ['3']
b = re.search('[0-9]','1abcd2') # <_sre.SRE_Match object; span=(0, 1), match='1'>
c = re.search('[0-9]','ab3cd2') # <_sre.SRE_Match object; span=(2, 3), match='3'>

# 如何取到匹配返回的值呢?
# 因为返回值可能是None 所以要做判断
if b:
print(b.group())

findall

1
2
3
4
# 
a = re.findall('[0-9]','abcde2') # ['2']
b = re.findall('[0-9]','1abcd2') # ['1', '2']
c= re.findall('[0-9]','ab3cd2') # ['3', '2']

使用实例

1
2
3
4
5
6
7
8
9
10
11
12
# 这俩效果一样  从头匹配
re.search('^ab','abc')

re.match('ab','abc')

# 从尾匹配
re.search('b$','ab')

# 注意 $ 不要跟match一起用
re.match('b$','b') # 能匹配
re.match('b.b$','bob') # 能匹配
re.match('b$','ab') # 不匹配

分组匹配

1
2
3
4
5
6
7
8
# 匹配 单词 和数字
re.search('[a-z]+[0-9]+','hjx123').group() # 'hjx123'

# 把 单词 和 数字分开
re.search('([a-z]+)([0-9]+)','hjx123').group() # 'hjx123'

# 再看
re.search('([a-z]+)([0-9]+)','hjx123').groups() # ('hjx','123')

非常炫酷的例子

1
2
3
4
5
6
7
8
9
# 模拟身份证号
s = '130704200005020613'
res = re.search('(?P<province>\d{3})(?P<city>\d+{3})(?P<born_year>\d{4})',s)
# 只要涉及分组就 groups
res.groups() # ('130','704','2000')

# 还能更NB
res.groupdict()
{"province":"130","city":"704","born_year":"2000"}

splitall 和 split

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 按数字分割
s = 'hjx22jack23rain31jin50'
re.split('\d',s) # ['hjx','','jack','','rain','','jin','']

re.split('\d+',s) # ['hjx','jack','rain','jin',''] 最后一个50后边又被分割出了


# 数字 或者 # 或者 - 分割
s2 = 'hjx22jack23rain31jin50#mock-Oldboy'
re.split('\d+|#|-',s2) # ['hjx', 'jack', 'rain', 'jin', '', 'mock', 'Oldboy']]

# 如果是 |分割的呢? 就 \|转义

# 如果字符是 \分割 在系统里会变成\\ 所以转义的时候要 \\\\
s3 = 'hjx22jack23ra\in31jin50#mock-Oldboy'
res3 = re.split('\d+|#|-|\\\\',s3)

split更强大的用法

1
2
3
4
5
6
s='9-2*5/3+7/3*99/4*2998+10*568/14'
re.split('[\*\-\/\+]',s)
# ['9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14']

re.split('[\*\-\/\+]',s,3)
# ['9', '2', '5', '3+7/3*99/4*2998+10*568/14']

sub

用于替换匹配的字符串

1
2
3
4
s = 'hjx22jack23ra\in31jin50#mock-Oldboy'
res = re.sub('\d','_',s) # hjx__jack__ra\in__jin__#mock-Oldboy

res2 = re.sub('\d','_',s,count=2) # hjx__jack23ra\in31jin50#mock-Oldboy

re.fullmatch(pattern, string, flags=0)

整个字符串匹配成功就返回re object, 否则返回None

1
re.fullmatch('\w+@\w+\.(com|cn|edu)',"alex@oldboyedu.cn")

最后一个

re.compile(pattern, flags=0)

1
2
3
4
5
prog = re.compile(正则) # 相当于把 正则 转换为代码规则 
result = prog.match(string) # 这样可以省略 正则规则转换的过程

以上俩行等价于
result = re.match(正则, string)

Flags标志符

  • re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
  • M(MULTILINE): 多行模式,改变’^’和’$’的行为
  • S(DOTALL): 改变’.’的行为,make the ‘.’ special character match any character at all, including a newline; without this flag, ‘.’ will match anything except a newline.
  • X(re.VERBOSE) 可以给你的表达式写注释,使其更可读,下面这2个意思一样
1
2
3
re.search('a','alex',re.I) # 忽略大小写

re.search('.','\n',re.S) # 匹配任意字符 . 是除了换行符 re.S代表任何字符