关于python中正则表达式的简明解析

本文介绍了Python正则表达式的基础知识,包括常用字符及其功能、匹配方法、贪心匹配与非贪心匹配,以及re.compile()的使用。通过实例展示了如何查找、替换和分组匹配文本,同时讲解了正则表达式的模式串构成和特殊字符的作用。
摘要由CSDN通过智能技术生成

目录

正则表达式的简单介绍

常用字符及其功能:

反斜杠 \ ——转义

圆括号()——分组

竖线  |  ——选择

问号 ?——匹配0或1次

加号 + ——匹配>=1次

星号 * ——匹配>=0次

花括号 {} ——指定匹配次数

方括号 [ ]  ——自定义字符分类

句点 . ——匹配除\n外的任意字符

插入字符 ^ ——指定从头开始匹配

美元字符 $ ——指定从末尾开始匹配

常用匹配方法:

.search()方法:一次查找到一个匹配项

.match()方法:只能从头开始匹配

.findall()方法:查找出所有匹配项

.sub()方法:对于匹配串进行替换

其他:

贪心匹配与非贪心匹配

关于re.compile()的第二个参数

总结


        这两天初步学习了一下python的正则表达式,在这篇博客里做个总结。

正则表达式的简单介绍:

        正则表达式(Regular Expression)是一种匹配文本的模式,可以利用它较为轻松地在很长一段文本中快速找到所需要一些信息(如号码、邮箱、网址url等)。调用正则表达式,首先需要导入re库:

import re

        正则表达式的核心是Regex对象(Regular Expression的缩写),即“模式串”, 通俗一点说也就是要按照这个串的格式在所提供的文本中查找相应格式的匹配串。创建Regex对象需要调用re.compile()方法:

import re

#re.compile(第一个参数:模式串, 第二个参数:特殊命令)

#下面创建一个11位的电话号码的模式串:
phonenumber = re.compile(r'\d{3}-?\d{4}-?\d{4}')

        如果不了解模式串中字符的特殊含义,刚看到这样一个串,肯定会觉得不知所云。那么下面我们便来了解一下模式串的构成和其中常见的几种特殊字符以及它们各自的作用。

        关于模式串:要先将其指定为原始字符串(在第一个引号前加上r),再写其中的内容

        模式串中的几类字符:

        1.确定的字符:0~9的数字、a~z的字母等,所看到的即是所能匹配到的

        2.字符分类:如上方代码中出现的\d,代表了所能匹配的一类字符。默认有三种,即\d——数字字符、\w——单词字符(包括数字、字母、下划线)以及\s——空白字符(包括空格、制表符、换行符);另外还可以通过[  ]自己进行设定(在下面会详细介绍)

        3.特殊字符:见下表

………………………………………………………………………………………………………………

        正则表达式中所有的特殊字符一览:

        ()        圆括号

        []        方括号

        {}        花括号

        \         反斜杠

        +        加号

        *        星号

        ?        问号

        |        竖线/管道(?)(C语言中的"按位或"运算符)

        .        句点

        ^        插入字符(caret)

        $        美元字符(dollar)

注意!对于上面所有列出的字符,如果需要在文本中进行匹配,一定要进行转义!

………………………………………………………………………………………………………………

这些字符都有其特殊功能,下面对这些字符的作用进行一一介绍:

反斜杠 \ ——转义

如果所要匹配的模式串中需包含上述特殊字符,则要在其前面加上\, 将其进行转义,否则系统会认为这些特殊字符仍然行使其特殊的功能,而出现错误。

import re

str = '?$*+'

#当没有进行转义时,找不到所需要的?字符串
Regex1 = re.compile(r'?')

match1 = Regex1.search(str)
print(match1.group())

#进行转义后可正常搜索
Regex2 = re.compile(r'\?')

match2 = Regex2.search(str)
print(match2.group())

#预期输出结果:
?

圆括号()——分组

原本的模式串可能是这样的:r'\d\d\d-\d\d\d\d-\d\d\d\d'

用()进行分组后,会变成这样:r'(\d\d\d)-(\d\d\d\d-\d\d\d\d)'

分组的意义——可以在后续查找操作中更轻松地获得匹配串中的某一部分(向.group()方法中传入参数),同时也便于其他特殊字符对于正则表达式中的一个片段进行操作。

import re

str = '132-456-1234'

Regex1 = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')

match1 = Regex1.search(str)
print(match1.group(1))
print(match1.group(2))

Regex2 = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
match2 = Regex2.search(str)
print(match2.group())


#预期输出结果:
123
456-1234

123-456-1234

竖线  |  ——选择

当想在一个模式串中设定多种不同的匹配模式时,| 字符便可以发挥作用了。

例如:r'Teacher|Student' 可以同时对Teacher和Student两个不同的串进行匹配

import re

str1 = 'Teacher and Student'
str2 = 'Student and Teacher'

Regex = re.compile(r'Teacher|Student')

match1 = Regex.search(str1)
print(match1.group())

match2 = Regex.search(str2)
print(match2.group())

#预期输出结果:
Teacher

Student

问号 ?——匹配0或1次

不确定所设定的字符或是分组在待查找文本中是否一定存在时,可以在这些字符或分组之后加上一个?号,即表示不管这些字符或分组中的内容是否一定出现,都可以被匹配上。

import re

str1 = 'the date is 2021/07/03'
str2 = 'the date is 20210704'

#在下面的正则表达式中,'/'、'-'、'|'三种连接符都会被匹配,无连接符的情况也可以被匹配
Regex = re.compile(r'\d{4}(/|-|\|)?\d{1,2}(/|-|\|)?\d{1,2}')

match1 = Regex.search(str1)
match2 = Regex.search(str2)
print(match1.group())
print(match2.group())


#预期运行输出:
2021/07/03
20210704

另外,?还与非贪心匹配相关联, 之后会进行详细介绍。

加号 + ——匹配>=1次

若设定了+号,则在所能匹配到的串中,在+号之前的字符或分组至少应出现一次,也可以出现多次。

import re

str = 'hahahahahage'

Regex = re.compile(r'(ha)+')

match = Regex.search(str)
print(match.group())

#预期输出结果:
hahahahaha

#我们会发现,输出的是匹配到的最长的串,这个问题涉及到后面的贪心与非贪心

        

星号 * ——匹配>=0次

与+号作用类似,*号也可以匹配多次,不过其最小匹配次数为0

import re

str = 'hahahahahage'

Regex = re.compile(r'(ge)*(ha)*')

match = Regex.search(str)
print(match.group())

#预期输出结果:
hahahahaha

花括号 {} ——指定匹配次数

当所需要的串中,某个部分出现次数有一个确定的范围时,可以使用花括号{}进行匹配次数的指定。

import re

str = 'hahahahahage'

#在{}内指定一个整数————匹配对应个数的前一字符或分组
Regex1 = re.compile(r'(ha){3}')
match1 = Regex1.search(str)
print(match1.group())

Regex2 = re.compile(r'(ha){4}')
match2 = Regex2.search(str)
print(match2.group())

#在{}指定一个a,b型的范围————匹配a~b个前一字符或分组
Regex3 = re.compile(r'(ha){3,5}')
match3 = Regex3.search(str)
print(match3.group())

#省略a————匹配0~b个
Regex4 = re.compile(r'(ha){3,}')
match4 = Regex4.search(str)
print(match4.group())

#省略b————匹配>=a个
Regex5 = re.compile(r'(ha){,4}')
match5 = Regex5.search(str)
print(match5.group())

#预期输出结果:

hahaha

hahahaha

hahahahaha

hahahahaha

hahahaha

方括号 [ ]  ——自定义字符分类

在模式串的第二类字符——字符分类(通俗地讲也就是多个字符的集合)中,我们不仅可以使用预设的\d、\w、\s三种类型,还可以自己设置所需要的类型。通过在中括号[ ]内放入所需要匹配的字符,可让这样的整体代表一系列字符的集合,从而实现更为自由的匹配


#    \d  相当于  [0-9]
#    \w  相当于  [a-zA-Z0-9_]
#    \s  相当于  [\n\t ] (最后一个是空格!)
#    \D  \d的补集,即除了数字之外的字
#    \W  \w的补集
#    \S  \s的补集

import re

#连续指定单个字符,则所有指定字符都会被匹配,如下面指定的元音字母
str1 = 'aeioubpmfgj'

Regex1 = re.compile(r'[aeiou]*')

match1 = Regex1.search(str1)
print(match1.group())

#预期输出结果:
aeiou


#还可以用'-'符号指定连续的一串字符(注意顺序)
str2 = 'thisislowercaseTHISISUPPERCASE'

Regex2 = re.compile(r'[a-z]+')

match2 = Regex2.search(str2)
print(match2.group())

#预期输出结果:
thisislowercase


Regex3 = re.compile(r'[A-Z]+')

match3 = Regex3.search(str2)
print(match3.group())

#预期输出结果:
THISISUPPERCASE


#上述两种操作也可以混合使用(直接将字符连在一起写)
str3 = '12345678999findnumber9'

Regex4 = re.compile(r'[a-z9]+')

match4 = Regex4.search(str3)
print(match4.group())

#预期输出结果:
999findnumber9


#在[]中的特殊字符不需要转义,同时‘-’字符也可以被匹配
str4 = '?$*+()-'

Regex5 = re.compile(r'[$?+*()^-]+')

match5 = Regex5.search(str4)
print(match5.group())

#预期输出结果:
'?$*+()-'
(不知道为什么,这一行要是不加引号单独写出来,整个代码段的语法高亮就全没了)

除了匹配所需要的部分字符外,还可以通过在[ ]的开头指定^字符来反向选择(即匹配不在[ ]中的所有字符)。

import re

str = 'abcdefghijklmnopqrstuvwxyz'

Regex = re.compile(r'[^a-q]+')

match = Regex.search(str)
print(match.group())

#预期输出结果:
rstuvwxyz

句点 . ——匹配除\n外的任意字符

句点可以匹配除了\n以外的所有字符,且一个句点对应一个字符

import re

str = 'my name is Nanami'

#使用.*可以匹配任意的文本
Regex = re.compile(r'my name is (.*)')

match = Regex.search(str)
print(match.group(1))

#预期输出结果:
Nanami

想要让 . 可以匹配所有字符,则需要在生成Regex时向recompile()函数传入第二个参数re.DOTALL(或者简写为re.S)。

import re

str = 'my name is Nanami\nKento'

Regex = re.compile(r'my name is (.*)', re.S)

match = Regex.search(str)
print(match.group(1))

#预期输出结果:
Nanami
Kento

插入字符 ^ ——指定从头开始匹配

美元字符 $ ——指定从末尾开始匹配

使用这两个字符可以对所匹配串进行更加严格的限定,如^限制必须以某种形式开头,而$限制必须以某种形式结尾

import re

str1 = 'Hello, Hana!'

Regex1 = re.compile(r'^Hello, (.*)!')

match1 = Regex1.search(str1)
print(match1.group(1))

Regex2 = re.compile(r'^hello, (.*)!')

match2 = Regex2.search(str1)
print(match2)

#预期输出结果:
Hana
None


str2 = 'Hana, bye!'

Regex3 = re.compile(r'(.*), bye!$')

match3 = Regex3.search(str2)
print(match3.group(1))

Regex4 = re.compile(r'(.*), Bye!$')

match4 = Regex4.search(str2)
print(match4)

#预期输出结果:
Hana
None


#联合使用两种字符,可以实现对整个串格式匹配的要求
str3 = 'Hello, Hana! きみがだいすきだよ!'

Regex5 = re.compile(r'^Hello, (.*)! きみがだいすきだよ!$')

match5 = Regex5.search(str3)
print(match5.group(1))

Regex5 = re.compile(r'^Hello, (.*)! きみがだいすきだ!$')

match5 = Regex5.search(str3)
print(match5)

#预期输出结果:
Hana
None

了解完模式串的构成,下面再来看看如何利用模式串来查找对应的文本:

.search()方法:一次查找到一个匹配项

在之前的示例代码中,可以看到很多诸如Regex.search(str)这样的语句,这实际上就是一种在文本中查找对应正则表达式的基本方式。

.search()方法会在整个给定文本中按顺序进行搜寻,直到找到第一个匹配串时停止,并将这个匹配串作为一个Match对象返回,Match对象的结构类似于这样:

如果没有匹配到任何串,则会返回None

对于Match对象,可以调用.group()方法,当不指定参数时,会返回整个匹配串;当所设定的模式串中有分组(  )的话,便可以向其中传入1,2…等参数,返回第1,2…个分组(若传入0,则和不指定的情况一样,返回整个串)。

import re

str = 'my phonenumber is 888-8888-8888, and my email is 1234567890@qq.com'

Regex = re.compile(r'.*(\d{3}-\d{4}-\d{4}).*\s(\d+@.*)')

match = Regex.search(str)
print(match.group(1))
print(match.group(2))
print(match.group(0))

#预期输出结果:
'''
888-8888-8888
1234567890@qq.com
my phonenumber is 888-8888-8888, and my email is 1234567890@qq.com
'''

.match()方法:只能从头开始匹配

这个方法相对于.search()而言更加原始,以至于我看的那本书上根本没有进行介绍,因此只能去阅读源码以及其他博主关于该方法的介绍

不难发现,这两种方法传参的形式完全一致,因此能用.match()的地方,.search()也一定能用,且效果更好,所以不再对.match()作过多介绍,只要知道它只能从头开始匹配,如果开头匹配不上就会返回None即可

另外好像还有一个.fullmatch()方法,用于查找完全匹配的文本,在这里也不再赘述。

.findall()方法:查找出所有匹配项

.findall()方法是.search()方法的升级版。.findall()方法的查找模式与.search()一致,但不同的是它在查找到第一个匹配项后不会立刻停下来,而是会继续查找,直到串尾,最终返回所有匹配项,若未找到则返回None。

import re

str1 = 'there is several decimal string, such as 123456789 and 987654321'

Regex1 = re.compile(r'\d+')

#使用.findall()方法时,返回一个由所有匹配到的串组成的列表
match1 = Regex1.findall(str)
print(match1)

#预期输出结果:
['123456789', '987654321']


str2 = 'there is several phonenumber, such as 123-456-7890 and 012-345-6789'

#当所设定的串中有分组时,将返回一个元组的列表,每个元组对应一个匹配串,而元组中的各元素则
#分别对应各个分组
Regex2 = re.compile(r'(\d+)-(\d+)-(\d+)')

match2 = Regex2.findall(str2)
print(match2)

#预期输出结果:
[('123', '456', '7890'), ('012', '345', '6789')]

.sub()方法:对于匹配串进行替换

.sub()方法在.findall()方法的基础上,又更进了一步,它不仅能够查找到所有匹配串,还能将匹配串中的内容替换成自己想要的内容。这个方法可以用于掩盖不想被别人看到的文本。

import re

#.sub()方法返回替换后的文本
str = 'my phonenumber is 123-456-7890'

Regex = re.compile(r'\d+-\d+-\d+')
print(Regex.sub('***-***-****', str))

#预期输出结果:
my phonenumber is ***-***-****

注意:以上方法均是基于Regex对象进行调用,即Regex.方法()的形式,而re库内还有一些与上述方法同名的方法,只不过其调用对象是re,即re.方法()的形式

用 re.方法() 的形式调用这些函数的时候,需要多传入一个参数pattern,作为模式串。而预先通过re.compile()函数设定好模式串要更加高效快捷,因此建议还是按照介绍,先将模式串做好,再来进行匹配。

贪心匹配与非贪心匹配:

Python正则表达式默认是“贪心”(greedy)的,即在有多个符合的匹配结果时,将会选择其中最长的作为匹配串。问号?字符可以让原本的“贪心”匹配变成“非贪心”,即选择最短的作为匹配串。

import re
str = 'haaaaaa'

#贪心匹配:
Regex1 = re.compile(r'ha+')
match1 = Regex1.search(str)
print(match1.group())

#预期输出结果————匹配到了最长的串:
haaaaaa


#非贪心匹配————在可能出现贪心匹配的地方之后加上?字符:
Regex2 = re.compile(r'ha+?')
match2 = Regex2.search(str)
print(match2.group())

#预期输出结果————匹配到了最短的串:
ha

关于re.compile()的第二个参数:

之前的介绍中,re.compile()函数用于生成一个模式串Regex,每次调用时我们一般都只传入了模式串格式这一个参数,但其实re.compile()还有第二个可选参数,常用的主要是以下三种:

1.re.IGNORCASE(简写为re.I)

传入这个参数,在所设定模式串中,英文字母大小写将会被忽略,即不论大写小写均可被匹配。

import re

str = 'There are 3 different names: Peter1, peter2, and PETER3'

Regex = re.compile('peter\d', re.I)

match = Regex.findall(str)
print(match)

#预期输出结果————三个peter均被匹配:
['Peter1', 'peter2', 'PETER3']

2.re.DOTALL(简写为re.S)

这个参数在前面的句点字符部分已经提到过,是用来让句点能够匹配所有字符的。

3.re.VERBOSE(简写为re.X)

这个参数主要是用来在正则表达式中添加注释,传入这个参数后,python将忽略模式串中的所有空白字符(空格、换行、制表)和注释,因此可以方便地对正则表达式中各分组的含义进行说明。

(下面的例子借用的是书上关于电话区号的)

phoneRegex = re.compile(r'''(
    (\d{3}|\(\d{3}\))?           # area code
    (\s|-|\.)?                   # separator
    \d{3}                        # first 3 digits
    (\s|-|\.)?                   # separator
    \d{4}                        # last 4 digits
    (\s*(ext|x|ext.)\s*\d{2,5})? # extension
    )''', re.X)

#在匹配时,模式串中的注释和空白都会被自动忽略

另外,这三个参数也可以结合起来使用,像下面这样:

Regex = re.compile(r'模式串', re.I|re.X|re.S)

总结:

这是目前为止写过最长的一篇博客了,断断续续写了两天,笼统地介绍了一下我所了解到的正则表达式。行文没什么逻辑,想到哪里写到哪里,中间有些用例的表述也不是十分清楚,希望之后能够不断改进,让自己的博客能够更加精致。(不过实话实说写将近万字的博客真的挺累的)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值