Python 正则表达式
正则简介
一、什么是正则表达式?
正则表达式本身与某种编程语言并没有什么实质性的联系,它只是匹配字符串内容的一种规则。官方的定义是,正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
二、应用领域
正则匹配可以应用于用户登录或注册时输入的用户名、密码、邮箱、手机号等信息是否合法;也可以应用于爬虫领域,从爬取的数据中过滤出想要的内容。既然正则表达式是一种匹配字符串的规则,所以正则表达式操作的对象一定是字符串对象。
三、正则在线测试工具
正则语法
一、字符组
在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[ ]表示。字符分为很多类,比如数字、字母、标点等等
[ ] 的使用
例如:
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
注:使用 “-” 时,必须由小到大写,如 0-9,a-z,A-Z,不能从大到小写,如 9-0,g-a,Z-B
二、元字符
. 匹配除换行符以外的任意字符
1 |
|
\w 匹配字母或数字或下划线
1 |
|
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾(边界)
1 |
|
^ 匹配字符串的开始
$ 匹配字符串的结尾
1 |
|
\W 匹配非字母或数字或下划线
1 |
|
\S 匹配非空白符
1 |
|
\D 匹配非数字
1 |
|
a|b 匹配字符a或者b
1 |
|
( ) 匹配括号内的表达式,也表示一个组
1 |
|
[ ] 匹配字符组中的内容
[^ ] 匹配非字符组中的所有内容
1 |
|
三、量词
? 重复一次或者零次(即当前字符可有可无)
+ 重复一次或多次(即当前字符至少出现一次)
* 重复零次或多次
{n} 重复n次
{n, } 至少重复n次
{n,m} 重复n到m次
四、正则匹配实例
. ^ $ 联合使用
正则 | 待匹配字符 | 匹配 结果 | 说明 |
---|---|---|---|
海. | 海燕海娇海东 | 海燕 海娇 海东 | 匹配所有"海."的字符 |
^海. | 海燕海娇海东 | 海燕 | 只从开头匹配"海." |
海.$ | 海燕海娇海东 | 海东 | 只匹配结尾的"海.$" |
? + * {} 联合使用
正则 | 待匹配字符 | 匹配 结果 | 说明 |
---|---|---|---|
李.? | 李杰和李莲英和李二棍子 | 李杰 李莲 李二 | ?表示重复零次或一次,即只匹配"李"后面一个任意字符 |
李.* | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 | *表示重复零次或多次,即匹配"李"后面0或多个任意字符 |
李.+ | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 | +表示重复一次或多次,即只匹配"李"后面1个或多个任意字符 |
李.{1,2} | 李杰和李莲英和李二棍子 | 李杰和 李莲英 李二棍 | {1,2}匹配1到2次任意字符 |
字符集 [] [^]
正则 | 待匹配字符 | 匹配 结果 | 说明 |
---|---|---|---|
李[杰莲英二棍子]* | 李杰和李莲英和李二棍子 | 李杰 李莲英 李二棍子 | 表示匹配"李"字后面[杰莲英二棍子]的字符任意次 |
李[^和]* | 李杰和李莲英和李二棍子 | 李杰 李莲英 李二棍子 | 表示匹配一个不是"和"的字符任意次 |
[\d] | 456bdha3 | 4 5 6 3 | 表示匹配任意一个数字,匹配到4个结果 |
[\d]+ | 456bdha3 | 456 3 | 表示匹配任意个数字,匹配到2个结果 |
分组( ) 或| [^] 联合使用
身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,
正则 | 待匹配字符 | 匹配 结果 | 说明 |
---|---|---|---|
^[1-9]\d{13,16}[0-9x]$ | 110101198001017032 | 110101198001017032 | 表示可以匹配一个正确的身份证号 |
^[1-9]\d{13,16}[0-9x]$ | 1101011980010170 | 1101011980010170 | 表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字 |
^[1-9]\d{14}(\d{2}[0-9x])?$ | 1101011980010170 | False | 现在不会匹配错误的身份证号了()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次 |
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ | 110105199812067023 | 110105199812067023 | 表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14} |
五、正则表达式小练习
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
六、特殊的用法和现象
量词 + ? 的用法
量词中的 ? + * {n,} 和 {n,m} 都是属于贪婪匹配,即尽可能多的匹配符合规则的字符,例如使用规则 ab{1,4} 去匹配 abbbbbbb,得到的结果是 abbbb,但是实际上 ab,abb,abbb 也是符合正则匹配的规则的,但是最后的结果还是以{1,4}中较大的范围优先,这就是贪婪匹配。
在正则内部,贪婪匹配是根据回溯算法来实现的。如,使用<.*> 规则去匹配<dshdksadk><dsahdksdjks>dhaskdksdjklsdjklsdj ,得到的结果为<dshdksadk><dsahdksdjks>,内部的匹配流程是从左往右分析规则,即从待匹配字符串离开时找,找到第一个 < 号,往后匹配所有字符,即匹配到结尾的 j ,此时规则发现是以 > 结尾的,就回头在找到这个符号为止。
而 “量词+?” 表示尽可能少的去匹配,即惰性匹配。如,使用<.*?> 规则去匹配<dshdksadk><dsahdksdjks>dhaskdksdjklsdjklsdj ,得到的结果为<dshdksadk>,内部实现的流程是规则在开始匹配时就会把 > 带着,一但找到这个符号,就不继续往后找了。
正则 | 待匹配字符 | 匹配 结果 | 说明 |
---|---|---|---|
李.*? | 李杰和李莲英和李二棍子 | 李 李 李 |
* 重复零次或多次,尽可能重复多次 *? 尽可能重复零次 |
李.+? | 李杰和李莲英和李二棍子 | 李杰 李莲 李二 |
+ 重复一次或多次,尽可能重复多次 +? 尽可能重复一次 |
李.?? | 李杰和李莲英和李二棍子 | 李 李 李 |
? 重复一次或零次次,尽可能重复一次 ?? 尽可能重复零次次 |
李.{1,4}? | 李杰和李莲英和李二棍子 | 李杰 李莲 李二 |
{n, m} 重复n次到m次,尽可能重复m次 {n, m}? 尽可能重复n次 |
李.{1,}? | 李杰和李莲英和李二棍子 | 李杰 李莲 李二 |
{n, }重复n次或多次,尽可能重复多次 {n, }? 尽可能重复n次 |
正则表达式中符号的转义
在字符组中一些特殊的字符会现出原形,如 [()+*?/$.] 就表示匹配对应的字符符号,原来的作用都不会生效,[-] 只有写在字符组的首位的时候表示普通的减号或者负号,写在其他位置的时候表示范围,如 [1 - 9],而所有的 \w \d \s(\n,\t, ) \W \D \S都表示它原本的意义,因此为了避免有的特殊符号在字符组中会产生特殊的作用,我们可以统一在这些符号前添加一个转义符 “\“
1 |
|
Python中使用正则
一、匹配相关
findall 方法
将所有匹配上的内容全部返回,返回值是一个列表;如果没有匹配结果,返回一个空列表
1 |
|
search 方法
如果匹配上了,返回一个正则匹配结果的对象,匹配不上返回None;通过group方法从对象中取值,但是只能拿到第一个值。
1 |
|
match 方法
和search方法一样,如果匹配上了,返回一个正则匹配结果的对象,匹配不上返回None;通过group方法从对象中拿到第一个值,但是match必须从头开始匹配
1 |
|
二、替换相关
sub 方法
将原字符串中对应字段替换成新规定的内容,返回替换后的结果,默认全部替换,可以指定替换的次数
1 |
|
subn 方法
将原字符串中对应字段替换成新规定的内容,返回值是一个元组,包含替换后的结果以及替换的次数,默认全部替换,可以指定替换的次数
1 |
|
三、切割相关
在原字符串中按照匹配的内容进行切割,返回值是一个列表,存放切割后的结果
1 |
|
四、进阶方法
compile 方法(时间效率)
对于python中的正则机制而言,其流程是先将正则表达式转换成python解释器能够理解的代码,再对字符串进行匹配,因此对于较长或者比较复杂的正则表达式,每次翻译解释就需要耗费一定的时间,如果频繁使用该正则,对整个任务的时间花费将会造成较大的影响。因此可以先使用compile方法,对正则表达式进行预编译,每次使用时直接使用预编译好的对象,从而节省时间。
注:只有在多次使用某一个相同的正则表达式的时候,这个compile才会帮助我们提高程序的效率
1 |
|
finditer 方法(空间效率)
如果匹配到的内容特别多,一次性读入内存,会影响代码的处理效率,因此可以使用finditer方法,返回一个迭代器,迭代器中存放的是正则匹配结果的对象,逐个取值,节省内存,提高效率。
1 |
|
五、分组相关
分组命名
- (?P
正则表达式) 表示给分组起名字 - (?P=name)表示使用这个分组,这里匹配到的内容应该和之前定义的分组中的内容完全相同
1 |
|
1 |
|
通过索引使用分组
不用给分组命名,直接使用分组的索引
1 |
|
python 中的正则表达式有着一些自己的特性:
- findall 方法中,正则规则出现分组,匹配的结果会优先显示分组的结果,要想取消分组优先,使用 (?:正则表达式)
1 |
|
- split 方法遇到分组,会保留切割的内容
1 |
|
- search中有分组的话,通过group(n)就能够拿到group中的匹配的内容
1 |
|
补:re 模块中,各个方法中的参数 flags
1 |
|
1 |
|