正则表达式规则:
一、字符组:[]
① 描述的是一个位置上能出现的所有可能性,一个括号只匹配一个字符的内容
②可以接受范围,是根据asc-ii码的范围进行匹配,只能从小到大,反过来就报错
例如:
[abc] 匹配a或b或c
[0-9] 匹配0到9中的一个数字
[a-z] 所有的小写字母
[A-Z] 所有的大写字母
[a-zA-Z] 大小写
[0-9a-zA-Z_] 数字字母下划线
二、其他元字符
\d 任意数字
\D 任意非数字
\s 空白
\S 非空白
\w 数字字母下划线
\W 非数字字母下划线
\t tab键
\n 换行符
. 匹配除了换行符之外的所有
[^] 非
^ 匹配字符串的开头
$ 匹配字符串的结尾:
例:判断用户注册的手机号是否合法,必须要有开头和结尾,不然1390000000113900000002也是合法的
^1[3-9]\d{9}$
| 或 ----a表达式|b表达式 匹配a或者b表达式中的内容,如果匹配a成功了,不会继续和b匹配。 所以,如果两个规则有重叠部分,总是把长的放在前面
() 约束
例如:www\.(baidu|jd|taobao)\.com
三、量词
{n} 表示匹配n次
{n,} 表示最少匹配n次
{n,m} 表示最少匹配n次,最多匹配m次
? 匹配0次或1次 {0,1}
* 匹配0次或n次 {0,}
+ 匹配1次或n次 {1,}
四、贪婪匹配和惰性匹配
① 贪婪匹配:在量词允许的情况下,尽量匹配多个
.x 表示匹配任意字符 任意多次数 遇到最后一个x才停下来
② 惰性匹配:在量词允许的情况下,尽量匹配少的内容,在量词后面加 ? 就是惰性匹配
.?x 表示匹配任意字符 任意多次数 但是一旦遇到x就停下来
五、转义符
① 原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义
\.
\*
\?
\(
\)
\+
② [().*+?] 所有的内容在字符组中会取消它的特殊意义
③ [a-c] -在字符组中表示范围,如果不希望它表示范围,需要转义,或者放在字符组的最前面或者最后面
六、re模块
- re模块中最重要的两个方法是findall 和 search
① 基本用法:
import re
s = '19740ash93010uru'
resp = re.findall("\d+", s)
print(resp) # ['19740', '93010']
resp1 = re.search("\d+", s)
print(resp1)
if resp1:
print(resp1.group()) # '19740'
由上面的例子可以看出:
findall是根据正则表达式,匹配出所有符合的字段。
search是根据正则表达式,找到第一个符合的字段,并且得通过group()方法获取字段的值
② 分组模式
我们常说的分组就是按括号分组,出现一个括号即为分组
例子:
import re
s = '19740ash93010uru'
# 一个括号的情况
resp = re.findall("9(\d)", s)
print(resp) # ['7', '3'] 优先显示括号匹配到的内容,以列表的形式返回
#两个以上括号
resp1 = re.findall("9(\d)(\d)(\d)", s)
print(resp1) #[('7', '4', '0'), ('3', '0', '1')] 显示括号匹配到的内容
# 按照完整的正则进行匹配,显示匹配到的第一个内容,但是我们可以通过给group方法传参数来获取具体文组中的内容
resp2 = re.search("9(\d)(\d)(\d)", s)
print(resp2) # <re.Match object; span=(1, 5), match='9740'>
print(resp2.group()) # 9740
print(resp2.group(1)) # "7"
print(resp2.group(2)) # "4"
print(resp2.group(3)) # "0"
看了例子应该能明白,为啥要使用分组,分组就是为了获取真正想要的内容。
如果实际工作中,遇到了不得已的情况加了括号,即用了分组的模式,为了不显示这个分组,可以用(?:),在分组的正则前加上?:就不会显示这个分组。
③ 分组命名
有种情况,就是分组比较多的时候,用group(n)再去获取的时候很难点清是第几个分组。这时候可以给分组命名一个别名,通过group(name)的形式获取内容。
(?P<分组名字>正则表达式)
读取:ret.group('名字')
例子:
import re
ret = re.search('\d(\d)\d(\w+?)(\d)(\w)\d(\d)\d(?P<name1>\w+?)(\d)(\w)\d(\d)\d(?P<name2>\w+?)(\d)(\w)','123abc45678agsf_123abc45678agsf123abc45678agsf')
print(ret.group('name1'))
print(ret.group('name2'))
另外一种情况,在做爬虫的时候,比如要获取一个网页标签内的真正的内容,由于标签的特殊性,开头<abc>,结尾就是</abc>,字符串是一致的,这时候就可以使用分组命名,结尾处引用之前的名字即可。
例子:
import re
exp= '<abc>akd7008&(&*)hgdwuih</abb>008&(&*)hgdwuih</abd>'
ret= re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',exp) # 通过?P=名字 的方式进行引用
ret= re.search(r'<(\w+)>.*?</\1>',exp) #也可以通过\1方式来说明我是引用的第几个命名(\1需要转义,也可前面加r),这种方式不常用
ret= re.search('<(\w+)>.*?</\\1>',exp)
print(ret)
④ 取消优先分组 (?:)
在遇到不得不使用括号的时候,括号内的内容会被当做分组给展示出来,如果不想要这个括号内的内容可以用(?:正则)的方式取消这个分组的显示。
⑤ flags 参数
re.I
IGNORECASE
忽略字母大小写
re.L
LOCALE
影响 “w, “W, “b, 和 “B,这取决于当前的本地化设置。
re.M
MULTILINE
使用本标志后,‘^’和‘$’匹配行首和行尾时,会增加换行符之前和之后的位置。
re.S
DOTALL
使 “.” 特殊字符完全匹配任何字符,包括换行;没有这个标志, “.” 匹配除了换行符外的任何字符。
re.X
VERBOSE
当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之后。
它也可以允许你将注释写入 RE,这些注释会被引擎忽略;
注释用 “#”号 来标识,不过该符号不能在字符串或反斜杠之后。
2.re 其他模块
① sub:替换, 可以通过参数控制替换几次,默认全部
import re
ret = re.sub('\d+', 'H', 'alex123wusir456', 1)
print(ret) # alexHwusir456
ret = re.sub('\d+', 'H', 'alex123wusir456', 2)
print(ret) # alexHwusirH
② subn :元组的方式返回,会多返回替换的次数
import re
ret = re.subn('\d+', 'H', 'alex123wusir456')
print(ret) # alexHwusirH
③ match: 会自动给正则加个 ^,主要是强调开头必须匹配
④ compile:可以节省代码的运行时间
# 假如一个正则需要匹配多次,compile达到了只解析一次重复使用的作用
ret = re.compile('\d+')
res1 = ret.search('alex37176')
res2 = ret.findall('alex37176')
print(res1)
print(res2)
⑤ finditer:节省代码空间,返回的是一个迭代器
ret = re.finditer('\d+','agks1ak018093')
for i in ret:
print(i.group())
# 1
# 018093
网友评论