Loading

正则表达式

前言

这里收集了在python中的正则表达式的常用使用方法,更多详细规则请移步官方文档

在线验证

进入网址,即可即时验证正则表达式处理是否正确。

匹配所有除换行符外的单个字符。

eg: .色即可匹配所有的“某色”词。

星号

表示匹配前面的子表达式的任意次,包括0次。

eg: 我想:.*。可匹配到包括“我想:”以及“。”在内的后面所有字符,即使“我想:”后面什么都没有也能匹配。

加号

表示匹配前面的子表达式的一次或多次,不包括0次。

eg: 我想:.*。可匹配到包括“我想:”以及“。”在内的后面所有字符,若“我想:”后面什么都没有则不能匹配到该行。

问号

表示匹配前面的子表达式0次或1次。

eg: 大?张伟则可以匹配到“张伟”和“大张伟”两个词。

花括号

花括号表示 前面的字符匹配 指定的次数

eg: 啦{3}只能匹配到“啦啦啦”,而不能匹配到“啦啦”、“啦啦啦啦”等更少或更多个“啦”的词,而啦{2,4}则能匹配到最少2个“啦”到最多4个“啦”之间的全由“啦”组成的词,啦{2,}则能匹配到最少2个“啦”的全由“啦”组成的词。

贪婪模式和非贪婪模式

"<html><head><title>Title</title>"在该字符串中想要获取到“<>”内的每个词的话,若直接使用<.*>则只能得到"<html><head><title>Title</title>"原原本本的一整串字符串,这是因为* , + , ?都是贪婪的,他们都会尽可能地囊括更大的范围,显然在该字符串中,第一个字符和最后一个字符恰好满足了匹配规则的首尾,而中间则全被.*匹配,无视中间出现的“>”字符。

要解决这个问题,就需要用到非贪婪模式,用法是在.*后面加?,变成.*?

对元字符的转译

如果我们要匹配的内容本身就包含前面的那些特殊字符如. , + , ? , *等,我们可以在这些字符前加上\即能匹配这些字符本身。

eg: 咦\?可以匹配“咦?”包含问好的词,若是没有反斜杠则?会作为特殊符号不会被匹配。

匹配某种字符类型

反斜杠后面接一些字符,表示匹配某种类型的一个字符。

\d匹配0~9之间的任意一个数字字符,等效于[0-9]

\D匹配除0~9外的任意一个字符,等效于[^0-9]

\s匹配任意一个空白字符,包括tab、换行、回车,等效于[\t\n\r\v\f]

\S匹配任意一个非空白字符,等效于[^\t\n\r\v\f]

\w匹配任意一个文字字符,等效于[0-9a-zA-Z_]

\W匹配任意一个非文字字符,等效于[^0-9a-zA-Z_]

\b不匹配任何字符,仅表示单词边界,例如,正则表达式\bcat\b可以匹配 "cat" 这个单词,但不能匹配 "category" 中的 "cat"

反斜杠也可以用在方括号里面,比如 [\s,.] 表示匹配 : 任何空白字符, 或者逗号,或者点

方括号

方括号表示要匹配 指定的几个字符之一 。

eg: [abc]匹配a,b或者c中的一个字符,等效于[a-c],中间的“-”表示范围从a到c。

另外,之前的特殊字符在方括号内也变得普通,不再具有特殊含义,如[akm.]匹配a,k,m或者“.”中的任意一个字符,这里的“.”在括号内只是普通字符,就匹配“,”这个字符本身。

起始、结尾位置和单行多行模式

^ 表示匹配文本的开头位置。

$ 表示匹配文本的结尾位置。

正则表达式可以设定单行模式多行模式

如果是单行模式,表示匹配整个文本的开头位置。

如果是多行模式,表示匹配文本每行的开头位置。

001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80

eg: ^\d+能匹配上面字符串中开头的数字,若为单行模式则只能匹配到“001”,而若为多行模式则下面两行的“002”和“003”也能匹配到,同理\d+$能匹配上面字符串末尾的数字,若为单行模式则只能匹配到“60”,而若为多行模式则下面两行的“70”和“80”也能匹配到。

竖线

|表示匹配其中之一。

要特别注意的是,竖线的优先级在正则表达式中是最低的,这就意味着,竖线隔开的部分就是一个整体。

eg: 黄色|绿中能匹配到“黄色”或“绿”,而不是“黄色”或“黄绿”。

括号

()称之为正则表达式的组选择

组就是把正则表达式匹配的内容其中某些部分标记为某个组,我们可以在正则表达式中标记多个组。

这能帮助我们在已经匹配到的内容里获取某些部分的核心。

eg: (.*),就能获得一句话中“,”前面的不包括“,”的所有字符,而若没有括号,则获得的字符会包含“,”。

content = '''苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的'''

import re
p = re.compile(r'^(.*),', re.MULTILINE) # 第二个参数代表设置为多行模式,缺省是单行模式
for one in  p.findall(content):
    print(one)

让点匹配换行符

有时候需要点匹配换行符,可以使用DOTALL参数。

p = re.compile(r'class=\"t1\">.*?<a>(.*?)</a>', re.DOTALL) # 现在'.'能够匹配诸如'\n'、'\r'之类的符号了

切割字符串

字符串的split方法只适用于简单的字符串切割,使用正则表达式让字符串切割变得更灵活吧。

import re

names = '关羽; 张飞, 赵云,   马超, 黄忠  李逵'

namelist = re.split(r'[;,\s]\s*', names)
print(namelist)

字符串替换

匹配模式替换

字符串的replace方法只适用于简单的字符串替换,使用正则表达式让字符串替换变得更灵活吧。

import re

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

newStr = re.sub(r'/av\d+?/', '/cn345677/' , names) # 第二个参数是替换的内容,第三个参数是原字符串
print(newStr)

sub方法也是替换字符串,但是被替换的内容用正则表达式来表示所有符合特征的字符串。

指定替换函数

刚才的例子中,我们用来替换的是一个固定的字符串 “/cn345677/”。

如果,我们要求,替换后的内容是原来的数字+6, 比如“/av66771949/”替换为“/av66771955/”。

怎么办?

这种更加复杂的替换,我们可以把 sub的第2个参数指定为一个函数,该函数的返回值,就是用来替换的字符串。

import re

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

# 替换函数,参数是 Match对象
def subFunc(match):
    # Match对象 的 group(0) 返回的是整个匹配上的字符串, 
    src = match.group(0)
    
    # Match对象 的 group(1) 返回的是第一个group分组的内容
    number = int(match.group(1)) + 6
    dest = f'/av{number}/'

    print(f'{src} 替换为 {dest}')

    # 返回值就是最终替换的字符串
    return dest

newStr = re.sub(r'/av(\d+?)/', subFunc , names)
print(newStr)

获取的组内字符串如下:

match.group(0) # 获取整个匹配字符串
match.group(1) # 获取第1个组内字符串
match.group(2) # 获取第2个组内字符串
# 在Python 3.6以后的版本有更简洁的写法如下:
match[0]
match[1]
match[2]

?xxpattern形式

?:pattern

匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。

?=pattern

正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

?!pattern

正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

?<=pattern

反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。

?<!pattern

反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。

posted @ 2021-09-12 17:17  白蜘蛛  阅读(129)  评论(0)    收藏  举报