搞懂Python正则表达式,这一篇就够了

科技资讯 投稿 25800 0 评论

搞懂Python正则表达式,这一篇就够了

本文代码基于Python3.11解释器,除了第一次示例,代码将省略 import re 这个语句

所有示例代码均可以在我的github仓库中的 code.py文件内查看

搞清楚Python正则表达式语法,这一篇就够了

1.Python正则表达式匹配文本模式方法

正则表达式是一种快速从文本中匹配对应模式文本的表达式,在Python中所有的正则表达式函数都在模块re中。

import re
mo1 = re.compile('Batman' # 先使用re的方法compile,compile的字符串参数便是一个正则表达式
# compile讲返回一个一个Regex对象,mo1就是对应正则表达式模式的对象
name1 = mo1.search('My favorite hero is Batman' # 使用mo1对象中search方法,这个方法的字符串参数就是需要被查找的字符串
# 匹配成功,那么将返回一个Match对象给name1,这个对象中有group(方法,它返回与正则表达式匹配的字符串(有些情况不全是字符串,我会在后面作解释
# 匹配失败,返回None
print(name1.group(

输出结果如下:

2.直接查找模式

2.1直接查找

Batman',则需要在字符串'My favorite hero is Batman',寻找'Batman'

2.2管道匹配多种模式

|’这个符号来表示管道匹配,即匹配多种可能

mo2 = re.compile(r'Batman|Superman'
name2 = mo2.search('My favorite hero is Superman'
print(name2.group(

正则表达式是'Batman|Superman',那么在search(的字符串参数中,与之匹配的是'Superman',那么返回的Match对象赋给name2,其方法group(返回’Superman‘

2.3管道匹配多种分组模式

可以,但可以用简洁的形式'(Bat|Super|Spiderman'

mo3 = re.compile('(Bat|Super|Spiderman'
name3 = mo3.search('My favorite hero is Spiderman'
print(name3.group(
print(name3.group(0  # 0默认是整个匹配的字符串
print(name3.group(1  # 1是匹配的第一个分组

search(进行匹配时,先匹配第一个分组’Bat‘’Super‘’Spider‘中的一个,再匹配’man‘;也可以认为是匹配’Batman‘'Superman''Spiderman'中的一个。

需要指出的是,在正则表达式中出现分组时,可以在group中传入参数,参数作为索引,比如在上述代码的group(1,此方法将返回第一个分组,同时,无参数或者参数为0则默认返回整个匹配文本

search(只会返回含有第一个出现的匹配文本的对象

mo4 = re.compile('(Bat|Superman'
name4 = mo4.search('I love Superman and Batman'
print(name4.group(  # 只输出第一个出现的Superman

运行结果如下:

Superman‘和'Batman'两个,但是name4对象的group方法只返回了第一个出现的'Superman'。

后面会有找到所有匹配文本的方法

3.查找固定类型字符模式

3.1字符类型

缩写字符 匹配字符
\d 0~9的数字
\D 除了0~9的其它字符
\w 字母,数字,下划线
\W 除了字符数字下划线
\s 空格制表换行符
\S 除了空格制表换行符

3.2固定类型模式

使用上面的缩写字符,可以匹配指定类型的字符

mo5 = re.compile(r'\d\d\d\d\d\d\d\d\d\d\d'
phone_number1 = mo5.search('我的电话号码是15600000000'
print(phone_number1.group(

比如,如果无r前缀,那么字符串中的'\n'将被解释为换行符,但是如果加上r前缀,那么会被解释为''和'n'两个字符。

mo = re.compile('\\d'
num = mo.search('abcd6ef'
print(num.group(

运行结果如下:

但是需要注意的是,以下几个在正则表达式中有特殊含义的字符即使前面有r,仍然要加转义字符''来匹配这些特殊字符

| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |

4.分组模式

有时我们需要给查找到的电话号码分段,比如前面的+86前缀,这时,就可以用到分组模式

mo5 = re.compile(r'(\+86(\d\d\d(\d\d\d\d(\d\d\d\d'
phone_number1 = mo5.search('我的电话号码是+8618900000000'
print('电话号码'+phone_number1.group(
print('前缀'+phone_number1.group(1

在书写正则表达式的时候,给前缀+86分了一组,其后按照我的阅读习惯,344数量格式再分了三组

字符串 组索引
+86 1
189 2
0000 3
0000 4

运行结果是

5.可有可无的分组的模式

mo6 = re.compile(r'(\+86?(\d\d\d(\d\d\d\d(\d\d\d\d'
phone_number2 = mo6.search('他输入了+8615600000000到电话框'
phone_number3 = mo6.search('另一个人输入18900000000'
print(phone_number2.group(
print(phone_number3.group(

在这个正则表达式中,我们对(+86进行可选匹配,匹配结果有'+86',返回字符串会带'+86',反之不带

第二个文本匹配返回对象中会包含返回'18900000000'的方法

6.含有特殊字符的模式

mo7 = re.compile(r'(\(\+\d\d\(\d\d\d(\d\d\d\d(\d\d\d\d'
phone_number4 = mo7.search('我的电话号码是(+8615600000000'
print(phone_number4.group(

r'(\(\+\d\d(\d\d\d(\d\d\d\d(\d\d\d\d'中,前缀r表示后面的字符串是原始字符串

模式 组索引
(+\d\d 1
\d\d\d 2
\d\d\d\d 3
\d\d\d\d 4

组1匹配小括号括起来的加号和两个数字

三个数字

四个数字

7.接收任意个数的字符的模式

0到多次,即在search(的文本中可以不出现也可以出现多次,示例代码如下:

mo8 = re.compile(r'\d*%'
money = mo8.search('本期涨幅有143%'
print(money.group(
money = mo8.search('本期涨幅为?%'
print(money.group(

在第一个正则表达式中,'\d*%'可以匹配'143%',其中'1' '4' '3'都与'\d'匹配

'\d*%'可以匹配'%',因为'%'前没有数字类型可以与'\d'匹配

8.接收一个存在的连续字符模式

1到多次,即在search(的文本中可以出现一次也可以出现多次,示例代码如下:

mo9 = re.compile(r'\d+'
numbers = mo9.search('第一产业增加值54779亿元'
print(numbers.group(

这个正则表达式中,可以匹配到'54779'这5个数字,其中每个数字型文本都与'\d'匹配

mo9 = re.compile(r'\d+亿元'
numbers = mo9.search('第一产业增加值????亿元'
print(type(numbers

这里如果我们直接输出numbers.group(返回字符串会报错。马上来解释,现在我们用type(函数测试一下变量numbers的数据类型

事实上,search(方法在找不到匹配文本时就会返回一个NoneType类型

*和+的区别

修饰字符 匹配文本出现次数
* 0到多次
+ 1到多次

不用出现;

必须出现。

9.字符匹配固定次数

9.1固定次数

如果'{}'括号内只有一个整数,如'\d{3}',表示只匹配3个数字类型字符

mo10 = re.compile(r'(\+\d\d?(\d{11}'
phone_number5 = mo10.search('电话号码是15600000000'
print(phone_number5.group(

这段代码中,正则表达式r'(\+\d\d?(\d{11}'表示'+\d\d'是可选匹配,可有可无,后面将匹配连续的11个数字类型字符,也就是说'15600000000'将匹配'\d'11次,运行结果如下:

我们试一试:

9.2次数范围

'{}'内可以用逗号把两个升序整数分开,比如'\d{11,13}',表示可以匹配11到13个数字字符

mo11 = re.compile(r'\+?\d{11,13}'
phone_number6 = mo11.search('电话号码是+8615600000000'
print(phone_number6.group(

正则表达式r'\+?\d{11,13}'表示'+'是可选匹配,而'\d{11,13}'将匹配11到13个数字类型字符,在被查找文本当中'+'匹配正则表达式的'\+?','8615600000000'匹配'\d{11,13}'

9.3贪心匹配与非贪心匹配

也就是说,正则表达式如果是'\d{4,6}?',那么,匹配结果是'1234',返回最少的字符。

# 贪心匹配方式
mo12 = re.compile(r'\d{3,5}'
num1 = mo12.search('数字有34567'
print(num1.group(  # 匹配最多的数字

# 非贪心匹配
mo13 = re.compile(r'\d{3,5}?'
num2 = mo13.search('数字有34567'
print(num2.group(  # 匹配最少的数字

运行结果:

9.4注意

2)'{}'允许'{3,3}'这样的写法,和'{3}'同义

*查找文本所有的匹配项findall(方法

上述用到的search(方法只能查找到第一个出现的匹配文本项,如何找到全部匹配项呢?

mo14 = re.compile(r'\d{11}'
phone_number7 = mo14.findall('电话号码1:15600000000'
                             '电话号码2:19100000000'
                             '电话号码3:18700000000'
print(phone_number7

我们想要在文本中找到所有和'\d{11}'能匹配的字符,'15600000000'等电话号码都可以和正则表达式匹配,findall(将返回一个包含这些匹配文本的字符串列表

findall(直接返回一个列表而不是Match对象,所以在上面千万别把print(phone_number7写成print(phone_number7.group(了。

这个返回结果不含有在正则表达式中未分组的部分

mo15 = re.compile(r'电话号码\d:(\d{3}(\d{4}(\d{4}'
phone_number8 = mo15.findall('电话号码1:15600000000'
                             '电话号码2:19100000000'
                             '电话号码3:18700000000'
print(phone_number8

这里,我们分别对电话号码 前三位,中间四位,最后四位 分组,那么单个匹配文本会被分成三个字符串,组成一个元组,而这些元组组合成一个列表

10.自定义匹配字符类型

10.1匹配指定字符

代码示例如下:

mo16 = re.compile(r'\b[aeiouAEIOU]\w*'
vowel_word = mo16.findall('I am obviously angry with you'
print(vowel_word

这里先介绍一下'\b'这个字符,这个字符将匹配单词的分界,也就是说将从一个单词开始匹配。

使用自定义匹配字符[aeiouAEIOU]匹配元音开头,'\w*'匹配除了空格,制表符,换行符外的字符。

10.2匹配指定的字符无需加\转义

但是,在指定字符匹配当中,无需加''转义,示例代码如下:

mo17 = re.compile(r'[*?+]+'
special_character = mo17.findall('*+?11*?'
print(special_character

在这个正则表达式中,特殊字符'*' '?' '+'前并未加''转义,将匹配连续的几个指定字符组成的字符串,被匹配文本中'*+?'和'*?'符合

10.3匹指定字符外的字符

代码如下:

mo18 = re.compile(r'\b[^aeiouAEIOU\n\t ]\w*'
non_vowel_word = mo18.findall('I am obviously angry with you'
print(non_vowel_word

在这个正则表达式中,'^'表示不匹配元音字符和换行符,制表符和' '空格符。也就是说,这个正则表达式匹配非元音字母开头单词

11.^和$在正则表达式中的作用

11.1^的作用

mo19 = re.compile(r'^(name:(\d+'
name_phone1 = mo19.search('name:15600000000这是信息的格式'
print(name_phone1.group(
name_phone1 = mo19.search('信息的格式是name:15600000000'
print(type(name_phone1

11.2$的作用

你知道我要说什么

mo20 = re.compile(r'(name:(\d+$'
name_phone2 = mo20.search('信息的格式是name:15600000000'
print(name_phone2.group(
name_phone2 = mo20.search('name:15600000000这是信息的格式'
print(type(name_phone2

与'^'相反,'$'字符将让正则表达式匹配字符串末尾的文本,比如上面的两个字符串,几乎可以直接推断出可以匹配的是第一个

12.通配字符‘.’,匹配除了换行符的所有字符

mo21 = re.compile(r'.at'
words = mo21.findall('The cat in the hat sat on the flat mat'
print(words

正则表达式将匹配末尾带有'at'的所有字符串,除了'at'位于一行开头这种情况,看看结果吧:

12.1 '.*'匹配所有的字符

'*'同样可以修饰'.',来达到匹配除了换行符外所有的字符的效果。

12.1.1贪心匹配(匹配最多的字符串)

mo22 = re.compile(r'names:(.* phone number:(.*'
users_info = mo22.findall('names:Mike phone number:15600000000 '
                          'names:Jack phone number:18100000000 '
                          'names:John phone number:16200000000 '
print(users_info

正则表达式将匹配'names:'开头加上其后的所有字符,直到遇到换行符或者字符串最后为止。

注意我这里的被查找字符串是由空格分开而非换行符,为方便看每行内容我用三个 '' 分开了字符串。

1)列表中只含一个元组,说明整个正则表达式只匹配了一个字符串

'names:'匹配了被查找字符串的'names:',正则表达式'(.'匹配了从'Mike'到'John'的所有字符,正则表达式' phone number:'匹配了被查找字符的'phone number:',第二个'(.'匹配了'16200000000'

12.1.2非贪心匹配(匹配最少的字符串)

mo23 = re.compile(r'names:(.*? phone number:(.*? '
users_info = mo23.findall('names:Mike phone number:15600000000 '
                          'names:Jack phone number:18100000000 '
                          'names:John phone number:16200000000 '
print(users_info

先来看看运行结果:

1第一组匹配:'names:'匹配'names:','(.*?'匹配'Mike',空格匹配空格,'phone number'匹配'phone number','(.*?'匹配'15600000000'

12.2 '.*'匹配换行符

事实上可以通过向compile(方法传关键字参数就可以让'.*'匹配换行符。

mo24 = re.compile('.*'
sentences = mo24.search("I can see empty streets.\nBut I can't sleep empty sheets\n"
print(sentences.group(

由于'.'不能匹配换行符,所以文本只能匹配到'I can see empty streets.'

现在我们将关键字实参re.DOTALL传入compile(方法

mo25 = re.compile('.*', re.DOTALL
sentences = mo25.search("I can see empty streets.\nBut I can't sleep empty sheets\n"
print(repr(sentences.group(
print(sentences.group(

容我先解释一下 repr(str函数的作用,它返回字符串str的原字符串,不进行转义。

'.*'将匹配所有的字符,那么,search(将要返回的是,包含所有被查找文本字符的对象

13.模糊大小写

我们在输入验证码验证自己不是机器人时,往往大小写均可以让自己通过。那么在正则表达式当中,我们也想在匹配时忽略大小写。只需要向compile(方法传入关键字实参re.IGNORECASE即可,速记一下就是ignore case大写并且去空格

mo26 = re.compile(r'england|china|america', re.IGNORECASE
country_name = mo26.search("THE PEOPLE'S REPUBLIC OF CHINA"
print(country_name.group(

由于大小写模糊,'CHINA'和正则表达式中的'china'匹配

14.更好得书写管理正则表达式

14.1多段 '' 连接

比如我们想在一串文本中找出大陆的电话号码,使用 r'' 分行并写下注释,那么可以通过以下示例代码查找:

mo27 = re.compile(r'(\+86?'  # 大陆电话前缀
                  r'(\d\d\d'  # 电话前三位
                  r'(\d\d\d\d'  # 电话中间四位
                  r'(\d\d\d\d'  # 电话后四位
phone_number9 = mo27.search('电话号码是:15600000000'
print(phone_number9.group(

运行结果:

14.2关键字实参re.VERBOSE

''' ''' 标识,来使正则表达式更易读。

mo28 = re.compile(r'''(\+86?  # 大陆电话前缀
                      (\d{3}  # 电话前三位
                      (\d{4}  # 电话中间四位
                      (\d{4}  # 电话后四位
                      ''', re.VERBOSE
phone_number10 = mo28.search('电话号码是:15600000000'
print(phone_number10.group(

运行结果:

15.多个关键字实参

mo = re.compile(r'',re.DOTALL,re.IGNORECASE

compile(最多只有两个参数。

可以在几个关键字实参之间用'|'间隔达到多个关键字实参的效果

mo29 = re.compile(r'nice to meet you,.*',re.DOTALL|re.IGNORECASE
response = mo29.search('NICE to Meet You,Sir.\nHow can I help you?'
print(repr(response.group(
print(response.group(

这样,既可以有 模糊大小写的效果,也有让 '.'匹配换行符的效果


感谢你阅读我的博客,如果你对我的内容有任何的意见、建议或者问题,欢迎在评论区留言,我会尽快回复。如果你发现了我的错误或者疏漏,也请不吝指正,我会及时修改。希望我的博客能对你有所帮助,也期待与你的交流和分享。

编程笔记 » 搞懂Python正则表达式,这一篇就够了

赞同 (115) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽