04 正则表达式

5月 11, 2020 716点热度 0人点赞 0条评论

4.1 正则表达式的简介

4.1.1 概念

正则表达式是用来匹配字符串的一种逻辑公式,就是用事先定义好的一些特定的字符及一些特定的字符组合,组合成一个“规则的字符串”(由字符A-Z以及特殊字符组成),用来将所规定好的字符进行搜索匹配。

4.1.2 应用场景
  • 表单验证(例子:邮箱、手机号、身份证等等。。)
  • 爬虫(爬取你要的东西)

4.2 正则表达式语法

4.2.1 普通字符

所有大小写字母、数字、汉字、下划线、所有标点符号以及其他符号,都是“普通字符”。在匹配的时候只匹配与本身相同的一个字符。例子:表达式c,在匹配字符串abcde的时候,匹配结果是:成功;匹配到的内容是c;匹配到的位置开始于2,结束与3(下标索引从0开始算起)。

match()函数
match(pattern, string, flags=0)
  • pattern 参数是正则表达式,如果匹配成功,则返回一个match对象,否则返回None
  • string 参数表示是要匹配的字符串
  • flag 参数标志是用来控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
4.2.2 元字符

正则表达式中使用了很多元字符,用来表示一些特殊的含义或功能。

表达式 匹配
. 小数点可以匹配处理换行符\n以外的任意字符
| 逻辑或操作符
[ ] 匹配字符集中的一个字符
[ ^ ] 对字符集求反,也就是上面的反操作。^尖号必须在方括号里的最前面
- 定义[ ]里的一个字符区间,例如:[a-z]
\ 对紧跟其后的一个字符进行转义
( ) 对表达式进行分组,将圆括号内的内容做一个整体,并获得匹配的值
4.2.3 转义字符

一些无法在书写或具有特殊功能的字符,采用在前面加上斜杆""进行转义的方法。

表达式 匹配
\r, \n 匹配回车和换行符
\t 匹配制表符
\ \ 匹配斜杆\
\ ^ 匹配^符号
\ $ 匹配$符号
\ . 匹配小数点

尚未列出的还有问号?星号*和括号等其他的符号。所有正则表达式中具有特殊含义的字符在匹配自身的时候,都要使用斜杆进行转义。这些转义字符的匹配用法与普通字符类似,也是匹配与之相同的一个字符

4.3 预定义匹配字符集

在正则表达式中的一些表示方法,可以同时匹配某个预定义字符集中的任意一个字符。比如,表达式\d可以匹配任意一个数字。虽然可以匹配其中任意字符,但是只能是一个,不是多个

表达式 匹配
\d 任意一个数字,0~9 中的任意一个
\w 任意一个字母或数字或下划线,也就是A-Z,a-z,0-9,_ 中的任意一个
\s 空格、制表符、换页符等空白字符的其中任意一个
\D \d的反集,也就是非数字的任意一个字符,等同于[^\d]
\W \w的反集,也就是[^\w]
\S \s的反集,也就是[^\s]

4.4 重复匹配

前面的表达式,无论是只能匹配一种字符的表达式可以匹配多种字符其中任意一个的表达式。都只能匹配一次。但是有时候我们需要对某个字段进行重复匹配,例如手机号0169999999,一般的新手可能会写成\d\d\d\d\d\d\d\d\d\d(这一种不是恰当的表达式),写着费劲又累又不恰当。

这种重复的字符可以使用表达式再加上修饰匹配次数的特殊符号{},可以实现重复匹配。例如:[abcd][abcd]可以写成[abcd]{2}

表达式 匹配
{n} 表达式重复n次,比如\d{2}相当于\d\d,a{3}相当于aaa
{m,n} 表达式重复m次,最多重复n次。比如ab{1,3}可以匹配ab或abb或abbbb
{m,} 表达式重复m次,比如\w\d{2,}可以匹配a12,_1111,M123等等
? 匹配表达式0次或者1次,相当于{0,1},比如a[cd]?可以匹配a,ac,ad
+ 表达式至少出现一次,相当于{1,},比如a+b可以匹配ab,aab,aaab等
* 表达式出现0次到任意次,相当于{0,1},比如\^*b可以匹配b,^^^b等

4.5 位置匹配和非贪婪匹配

4.5.1 位置匹配

有时候我们对匹配的出现位置有要求,比如开头、结尾、单词之间等等

表达式 匹配
^ 在字符串开始的地方匹配,符号本身不匹配任何字符
$ 在字符串结束的地方匹配,符号本身不匹配任何字符
\b 匹配一个单词边界,也就是单词和空格之间的位置,符号本身不匹配任何字符
\B 匹配非单词边界,即左右两边都是\w范围或者左右两边都不是\w范围时的字符缝隙
4.5.2 贪婪与非贪婪模式

在重复匹配时,正则表达式默认总是尽可能多的匹配,这被称为贪婪模式。例如:针对文本dxxxdxxxd,表达式(d)(\w+)(d)中的\w+将匹配第一个d和最后一个d之间的所有字符xxxdxxx。可见,\w+在匹配的时候,总是尽可能的匹配符号它规则的字符。同理,带有? *和{m,n}的重复匹配表达式都是尽可能地多匹配

效验数字的相关表达式:

功能 表达式
数字 ^[0-9]*$
n位的数字 ^\d{n}$
⾄少n位的数字 ^\d{n,}$
零和⾮零开头的数字 ^(0|[1-9][0-9]*)$
有两位⼩数的正实数 ^[0-9]+(.[0-9]{2})?$
⾮零的负整数 ^-[1-9]\d*$
⾮负浮点数 ^\d+(.\d+)?$
浮点数 ^(-?\d+)(.\d+)?$

特殊场景表达式:

功能 表达式
Email地址 ^\w+([-+.]\w+)@\w+ ([-.]\w+).\w+([-.]\w+)*$
域名 [a-zA-Z0-9][-a-zA-Z0-9] {0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
⼿机号码 ^(+?6?01)[0-46-9]-*[0-9]{7,8}$
⽇期格式 ^\d{4}-\d{1,2}-\d{1,2}
身份证 \d{6}-\d{2}-\d{4}
空白行的正则表达式 \n\s*\r (可以⽤来删除空⽩⾏)
IP地址提取 \d+.\d+.\d+.\d+ (提取IP地 40 址时有⽤)

4.6 re模块使用方法

提供了下⾯的⽅法进⾏字符串的查找、替换和分割等各种处理操作

方法 描述 返回值
compile(pattern[, flags]) 根据包含正则表达式的字符串创建模式对象 re对象
search(pattern, string[, flags]) 在字符串中查找 第⼀个匹配到的对象或 者None
match(pattern, string[, flags]) 在字符串的开始处匹配模式 在字符串开头匹配到的 对象或者None
split(pattern, string[, maxsplit=0,flags]) 根据模式的匹配项来分割字符串 分割后的字符串列表
findall(pattern, string,flags) 列出字符串中模式的所有匹配项 所有匹配到的字符串列表
sub(pat,repl, string[,count=0,flags]) 将字符串中所有的pat的匹配项⽤repl替换 完成替换后的新字符串
compile(pattern, flags=0

这个方法是re模块的工厂方法,用于将字符串形式的正则表达式编译成为pattern模式对象,可以实现更高效率的匹配。第二个参数flag是匹配模式。

使用compile()完成一次转换后,再次使用该匹配模式的时候就不用进行转换了。经过compile()转换的正则表达式对象也能使用普通的re方法。其用法如下:

import re
pat = re.compile(r"abc")    # r"\d" 原生字符串(解决反斜杠的问题)
pat.match("abc123")
# <_sre.SRE_Match object; span=(0, 3), match='abc'>
flag匹配模式

re模块提供了一些可选的标志修饰来控制匹配的模式。可以同时指定多种模式,通过与符号|来设置多种模式共存。如re.l | re.M 被设置成I和M模式。

匹配模式 描述
re.A ASCII 字符模式
re.l 使匹配堆大小写不敏感,也就是不区分大小写的模式
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响^和$
re.S 使 . 这个通配符能够匹配包括换行在内的所有字符,针对多行匹配
re.U 根据Unicode字符集解析字符。这个标志影响 \w,\W,\b,\B
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解
search(pattern, string, flag=0)

在文本内查找,返回第一个匹配到的字符串。它的返回值类型和使⽤⽅法与 match()是⼀样的,唯⼀的区别就是查找的位置不⽤固定在⽂本的开头。

obj = re.search(r"abc","123abc456abc789")
# <_sre.SRE_Match object; span=(3, 6), match='abc'>

obj.group()
# 'abc'
obj.start()
# 3
obj.end()
# 6
obj.span()
# (3, 6)
findall(pattern, string, flags=0)

作为re模块得三大搜索函数之一,findall()和match()、search()得不同之处在于,前两者都是单值匹配,找到一个就忽略后面,直接返回不再查找了。而findall是全文查找,它的返回值是一个匹配到的字符串的列表。这个列表没有group()方法,没有start、end、span,更不是一个匹配对象,仅仅是个列表!如果一项都没有匹配到那么返回一个空列表。

import re
obj = re.findall(r"abc","123abc456abc789")
# ['abc', 'abc']
split(pattern, string, maxsplit=0, flags-0)

re模块的split()方法和字符串的split()方法很相似,都是利用特定的字符去分割字符串。但是re模块的split()可以使用正则表达式,因此更灵活,更强大。

import re
s = "8+7*5+6/3"
a_list = re.split(r"[\+\-\*\/]",s)
# ['8', '7', '5', '6', '3']

split有个参数maxsplit,用于指定分割的次数:

a_list = re.split(r"[\+\-\*\/]",s,maxsplit= 2)
a_list
# ['8', '7', '5+6/3']
sub(pattern, repl, string, count=0, flags=0)

sub()方法类似字符串的replace()方法,用指定的内容替换匹配到的字符,可以指定替换次数。

s = "i am jack! i am nine years old ! i like swiming!"
import re
s = re.sub(r"i","I",s)
# 'I am jack! I am nIne years old ! I lIke swImIng!'

4.7 分组功能

Python的re模块有一个分组功能。所谓的分组就是去把已经匹配到的内容再筛选出需要的内容,相当于二次过滤。实现分组靠括号(),而获取分组的内容靠的是group()、groups(),其实前面我们已经展示过。re模块里的几个重要方法在分组上,有不同的表现形式,需要区别对待。

YY部落站(Admin)

当你能梦的时候就不要放弃梦~😎

文章评论