4-02python语法基础-内置模块-re模块(用于字符串处理)
python正则
- 1,我要用人类的语言把这个正则再梳理一遍
- 2,是正则表达式本身的逻辑要搞清楚,因为正则表达式是做字符串匹配的,任何语言都有这个,python是re模块
- 3,主要依托于python的re模块的操作,python的re模块,是怎么操作正则的,
- 4,记住,正则表达式只和字符串匹配有关系,和其他的数据类型没有关系,
- 5,应用非常的广泛,比如手机号,比如身份证号,比如邮箱,
- 6,使用场景法学习,
- 使用这两个教程来学习:
https://www.runoob.com/regexp/regexp-tutorial.html
https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md - 这是在线测试工具:http://c.runoob.com/front-end/854
先学习正则表达式本身的逻辑
废话不多说,首先学习元字符的概念,这是必会的基础,
正则表达式-基本匹配
举例:The fat cat sat on the mat.
一段文本,里面有the这个单词,我想要把里面的the全都找出来,就可以输入正表达式:the,就会把整段文本里面所有的the全都找出来,
这就是基本匹配
import re
str1 = "The fat cat sat on the mat.the"
print(re.findall("the", str1))
输出一个列表:['the', 'the']
注意1,正则表达式是大小写敏感的,所以大写的The,是匹配不到的,
正则表达式-元字符
这个元字符是相当的重要,正常情况基本不会使用上面的基本匹配,而都是使用这个元字符,
每一个元字符都是特殊含义的,
第一个,最重要的,点运算符
举例:The car parked in the garage.
这个点,是匹配任意单个字符,但是不包括换行符,
我们现在输入正则:.ar,这个执行逻辑是什么:就是每一个字符去找,然后后面紧邻ar的,所以会有3个结果,
注意1,这个点,是匹配的任意单个字符,注意是单个,
import re
str1 = "The car parked in the garage."
print(re.findall(".ar", str1))
输出一个列表:['car', 'par', 'gar']
所以你看到这个输出的结果,要和上面的基本匹配做区分
import re
str1 = "The car parked in the garage."
print(re.findall("ar", str1))
输出结果:['ar', 'ar', 'ar']
第二个,字符集,使用方括号,[]
举例:The car parked in the garage.
这个我们想要找到the和The,怎么办?
我们输入正则:[Tt]he,这个执行逻辑是怎么,就是The,the,然后全局去找这两个字符串,就会有两个结果,
举例2:A garage is a good place to park a car.
我们输入正则:car[.],方括号的句号就表示句号。
import re
str1 = "The car parked in the garage."
print(re.findall("[Tt]he", str1))
输出结果:['The', 'the']
常见的字符集的写法:
[0123456789] 匹配所有数字
[0 - 9] 匹配所有数字
[a-z] 匹配所有的小写字母
[A-Z] 匹配所有的大写字母
[0-9a-zA-Z] 匹配大小写字母和所有的数字,
import re
str1 = "The car parked in the garage.111"
print(re.findall("[0-9]", str1))
输出结果:['1', '1', '1']
否定字符集
举例3:The car parked in the garage.
我们输入正则:[^c]ar 匹配一个后面跟着ar的除了c的任意字符。
import re
str1 = "The car parked in the garage.111"
print(re.findall("[^c]ar", str1))
输出结果:['par', 'gar']
正则表达式-简写字符集
上面我们说了方括号,里面是表示的字符集,下面是一些简写的字符集,
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线,word的意思,
\s 匹配任意的空白符,space的意思
\d 匹配数字,digit的意思
\n 匹配一个换行符,enter回车的意思
第三个,重复次数,
元字符 +,* or ? 的,用来指定匹配子模式的次数。 这些元字符在不同的情况下有着不同的意思。
*号
举例:The car parked in the garage
表达式 a* 匹配0或更多个以a开头的字符。
我们输入正则:[a-z],这是匹配一个行中所有以小写字母开头的字符串。
注意2,,这个代表的是匹配前面的子表达式零次或多次,这种方式没找到也算一个结果,
+号
举例2,The fat cat sat on the mat.
+号匹配+号之前的字符出现 >=1 次。 例如表达式c.+t 匹配以首字母c开头以t结尾,中间跟着至少一个字符的字符串。
?号
举例3,The car is parked in the garage.
在正则表达式中元字符 ? 标记在符号前面的字符为可选,即出现 0 或 1 次。 例如,表达式 [T]?he 匹配字符串 he 和 The。
第四个,花括号,{}
举例:The number was 9.9997 but we rounded it off to 10.0.
在正则表达式中 {} 是一个量词,常用来限定一个或一组字符可以重复出现的次数。 例如, 表达式 [0-9]{2,3} 匹配最少 2 位最多 3 位 0~9 的数字。
我们可以省略第二个参数。 例如,[0-9]{2,} 匹配至少两位 0~9 的数字。
如果逗号也省略掉则表示重复固定的次数。 例如,[0-9]{3} 匹配3位数字
第五个:分组,()
特征标群是一组写在 (...) 中的子模式。(...) 中包含的内容将会被看成一个整体,和数学中小括号( )的作用相同。
例如, 表达式 (ab)* 匹配连续出现 0 或更多个 ab。如果没有使用 (...) ,那么表达式 ab* 将匹配连续出现 0 或更多个 b 。
再比如之前说的 {} 是用来表示前面一个字符出现指定次数。但如果在 {} 前加上特征标群 (...) 则表示整个标群内的字符重复 N 次。
举例:The car is parked in the garage.
我们还可以在 () 中用或字符 | 表示或。例如,(c|g|p)ar 匹配 car 或 gar 或 par.
注意1,这个括号里面是一个组合了,这个并且的关系,而[ab]这个就是或的关系,
注意2:分组的命名,(?
第六个,或运算符,|
举例:The car is parked in the garage.
或运算符就表示或,用作判断条件。(T|t)he|car 匹配 (T|t)he 或 car。
第七个,转码特殊字符,\
如果就是想要匹配\d怎么办?
就需要转译,\d,这种就是转义了,
如果我想要匹配: \d 怎么办,就要使用\\d,每一个反斜杠都要 转义,
第八个,锚点
在正则表达式中,想要匹配指定开头或结尾的字符串就要使用到锚点。
^ 指定开头,
^ 用来检查匹配的字符串是否在所匹配字符串的开头。
例如,在 abc 中使用表达式 ^a 会得到结果 a。但如果使用 ^b 将匹配不到任何结果。因为在字符串 abc 中并不是以 b 开头。
举例:The car is parked in the garage.
例如,^(T|t)he 匹配以 The 或 the 开头的字符串。
注意这个开头,是整个字符串的开头,
$ 指定结尾。
$ 号用来匹配字符是否是最后一个。
举例:The fat cat. sat. on the mat.
例如,(at.)$ 匹配以 at. 结尾的字符串。
正则表达式-贪婪和懒惰
正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用 ? 将贪婪匹配模式转化为惰性匹配模式。
贪婪匹配,一直往后匹配
加问号,是惰性匹配,
.*?的用法,
. 是任意字符,* 是取 0 至 无限长度,? 是非贪婪模式。
合在一起就是:取尽量少的任意字符,一般不会这么单独写,他大多用在:.*?x
就是取前面任意长度的字符,直到一个x出现
上面就是正则的规则了,学会了这些就够你使用的了
需要灵活使用这些,这个规则是不会改变的,
re模块常用的api
使用findall,开始匹配字符串
ret = re.findall("[a-z]+","abc aaa an")
print(ret) # ['abc', 'aaa', 'an'],这是放到列表中,
还可以使用search,匹配字符串
ret = re.search("[a-z]+","abc aaa an").group()
print(ret) # ['abc', 'aaa', 'an'],这是放到列表中,
注意:这个search是只匹配一次,找到一个就返回,不往后找了,而且一定要使用group才会出结果,
如果结果找不到就会报错,报错是因为结果是none所以调用group会报错的,
因为会报错,所以一般是这么写:
ret = re.search("aaa","abc aaa an")
if ret:
ret = ret.group()
print(ret)
else:
print("找不到")
print(ret.group(1)) # 这是取值第一个分组,现在就是只有一个分组,818
所以你就知道为什么要使用group了,
还可以使用match,匹配字符串
match是从头匹配,如果匹配上就会返回一个变量,然后使用group显示,
匹配不上,就是none使用group会报错,
因为会报错,所以一般是这么写:
ret = re.match("aaa","abc aaa an")
if ret:
ret = ret.group()
print(ret)
else:
print("找不到")
match 和 search 是匹配一次
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
split,分隔字符串
ret = re.split("[ab]","abcd")
print(ret) # ['', '', 'cd']
为什么是这个结果,因为是按照a和b分割,先按照a,然后按照b,这个不太常用
sub,替换字符串
ret = re.sub("\d","H","eefeflef4fefe4",1)
print(ret)
这个方法是替换,把第一个参数替换成为第二个参数,文本就是第三个,替换次数就是第四个参数,不写的还就是全部替换,
ret = re.subn("\d","H","eefeflef4fefe4",1)
print(ret) # ('eefeflefHfefe4', 1)
这个方法不只是把替换的结果返回来,还会把替换的次数给你返回回来,
compile,正则对象
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
如果你想要把一个正则规则反复使用,或者这个规则非常长的时候可以使用一个方法
obj = re.compile("\d{3}") # 可以反复使用这个正则,
ret = obj.search("abc123afdfadsf")
print(ret.group())
finditer,迭代器
ret = re.finditer('\d', 'ds3sy4784a') # finditer返回一个存放匹配结果的迭代器
print(ret) # <callable_iterator object at 0x10195f940>
print(next(ret).group()) # 查看第一个结果
print(next(ret).group()) # 查看第二个结果
print([i.group() for i in ret]) # 查看剩余的所有结果