- 正则表达式字符串
- 元字符
- 转义字符
- 开始与结束符
- 字符类
- 定义字符类
- 字符类取反
- 区间
- 预定义字符类
- 量词
- 量词的使用
- 贪婪和懒惰
- 分组
- 分组的使用
- 分组命名
- 反向引用分组
- 非捕获分组
- re模块
- search()和match()函数
- findall()和finditer()函数
- 字符串分割
- 字符串替换
- 是什么:Regular Expression,简写RE,是预先定义好的一个“规则字符串”,通过这个规则字符串可以匹配、查找和替换那些符合规则的文本。
- 优点:文本的查找替换虽然可以使用字符串提供的方法实现,但是实现较为困难,运算效率低。使用正则效率高。
- 缺点:编写合适的正则表达式较为困难。
- python中应用:数据挖掘、数据分析、网络爬虫、输入有效性验证等待。
- 正则表达式是一种字符串,它由普通字符和元字符组成的。
- 普通字符:按照字符字面意义的字符。
- 元字符:预先定义好的一些特定字符。
- 如验证邮箱的正则表达式:w+@zhengzetang.com,其中w+、.属于元字符;@zhengzetang、com是普通字符。
- 用来描述其他字符的特殊字符,由基本元字符和普通字符构成,基本元字符是构成元字符的组成要素。基本元字符有14个,如下表
- 以上面匹配邮箱的字符串w+@zhengzetang.com为例
- w字符不表示英文字母w,而是表示任何语言的单词字符、数字或下划线等内容时,需要在w前面加上反斜杠“”。
- .本身是基本元字符,代表任意一个字符,但是我们希望按照.字面的意义使用(就是一个点),这时候加上一个反斜杠“”就可以实现了。
- 转义字符就是对普通字符或基本元字符,进行转义,用于其他功能。
- 前面提到了^和$,用以匹配一行字符串的开始和结束。
- 当以^开始时,要求一行字符串的开始位置匹配。
- 当以$结束时,要求一行字符串的结束位置匹配。
import re p1 = r'w+@tianshangrenjian.com' p2 = r'^w+@tianshangrenjian.com$' text = "My email is tong_guan588@tianshangrenjian.com." m = re.search(p1, text) print(m) # 匹配不到,有^,$符号,匹配时要求text字符串开始和结束都要与正则表达式开始和结束匹配。 a = re.search(p2,text) print(a) # email字符串的开始与结束与正则表达式相匹配 email = 'tong_guan588@tianshangrenjian.com' b = re.search(p2, email) print(b)
- 显示结果
- 正则表达式种可以使用字符类(character class),一个字符类定义一组字符,其中的任一字符出现在输入字符串中即匹配成功。
- 注意:每次匹配只能匹配字符串中的一个字符。
- 定义一个普通的字符类,使用[]元字符类。例,想在字符串中匹配java或Java,可以使用正则表达式[Jj]ava
import re p = r'[Jj]ava' # 可以匹配 m = re.search(p, 'i like Java and Python') print(m) # 可以匹配 c = re.search(p, 'i like java and Python') print(c) # 不可匹配 b = re.search(p, 'i like JAVA and Python') print(b) # 想要匹配JAVA,可以使用| p2 = r'java|JAVA|Java' d = re.search(p2, 'i like JAVA and Python') print(d)
- 运行结果为
- 在正则表达式中指定不想出现的字符, 可以在字符前加^符号。
import re p = r'[^0123456789]' # 不匹配数字 m = re.search(p, '239120392') print(m) # 除了非数字外,都可以匹配任意字符 a = re.search(p, 'Reasdskf') print(a)
- 运行结果
- 如果要表示连续的数字,用[^0123456789],较为复杂,可以使用区间符号-表示。即[^0123456789]等同于[^0-9]
- 连续的英文字母可以表示为[a-z],大写[A-Z]。
- 可以表示多个不同区间,如[A-Za-z0-9]表示所有字母和数字字符类,[0-25-7]表示0,1,2,5,6,7
import re p = r'[a-zA-Z0-9]' # 匹配 m = re.search(p, 'A10.3') print(m) # 不匹配 a = re.search(r'[0-25-7]', 'A3489C') print(a)
- 有些字符很常用,如[0-9]等,为了书写方便,正则表达式提供了预定义的字符类。
- 示例
import re # p = r'[^0123456789]' p = r'D' # 不匹配 m = re.search(p, '11003') print(m) # 匹配 a = re.search(p, 'ajdka') print(a) text = "hello world。" b = re.search(p, text) print(b)
- 运行结果
- 上面说的正则,只能匹配显示一次字符或字符串,如果想匹配显示多次字符或字符串可以使用量词。
- 量词表示字符或字符串重复的次数,量词如下表
字符 | 说明 |
---|---|
? | 出现零次或一次 |
* | 出现零次或多次 |
+ | 出现一次或多次 |
{n} | 出现n次 |
{n, m} | 至少出现n次但不超过m次 |
{n, } | 至少出现n次 |
- 示例
import re m = re.search(r'd?', '87654321') # 出现数字一次,匹配字符8 print(m) a = re.search(r'd?', 'adxcx') # 出现数字0次,匹配'' print(a) b = re.search(r'd*', '2134354afas123') # 出现数字多次,匹配2134354 print(b) c = re.search(r'd{8}', '87654321') # 出现数字8次,匹配87654321 print(c) d = re.search(r'd{9,}', '87654321') # 出现数字8次,但要求9次,不匹配 print(d)
- 运行结果
- 量词细分为贪婪量词和懒惰量词。
- 贪婪量词会尽可能多地匹配字符,懒惰量词会尽可能少地匹配字符。
- 大多数计算机语言的正则表达式词默认是贪婪的,要想使用懒惰量词在量词后面加 ?
import re # 使用贪婪量词 m = re.search(r'd{5,8}', '87456123') # 至少出现5次,不少于8次,贪婪匹配8次 print(m) # 使用懒惰量词 a = re.search(r'd{5,8}?', '87456123') # 懒惰匹配5次 print(a)
- 运行结果
- 分组也称为子表达式,就是将一个字符串放到一对小括号中,让一个字符串作为整体使用量词。
-
对正则分组不仅可以对一个字符串整体使用量词,也可以在正则中引用已存在的分组。
-
示例
import re p = r'(121){2}' m = re.search(p, '121121121adfd') # 匹配121121 print(m) print(m.group()) # 返回匹配的字符串 print(m.group(1)) # 返回第一组内容 a = r'(d{3,4})-(d{7,8})' b = re.search(a, '010-7785457322a') print(b) print(b.group()) print(b.group(1))
-
运行结果
- 组命名:在组开头添加?P<分组名>
- 分组命名后,方便程序访问分组。
- 示例
import re p = r'(?Pd{3,4})-(?P
d{7,8})' b = re.search(p, '010-77548573') print(b) print(b.group()) print(b.groups()) # 通过组编号返回 print(b.group(1)) print(b.group(2)) # 通过组名返回 print(b.group('area_code')) print(b.group('phone_code')) - 运行结果
- 要说清这个意思,我们先举个例子,如果要解析XML代码
import re p = r'<([w]+)>.*([w]+)>' m = re.search(p, 'abc') print(m) a = re.search(p, 'erd') print(a)
- 运行结果,a不是我们想要的,但是也能匹配出来,怎么办呢?
- 分析正则表达式
- 如上图,正则的两个分组内容一样,但是匹配出来的与不一样,因此上述正则不能实现我们想要的结果。如果把第二个分组改成反向引用第一组,即可实现,组编号都是从1开始的,反向引用语法为:组编号。
import re p = r'<([w]+)>.*(1)>' m = re.search(p, 'abc') print(m) a = re.search(p, 'erd') print(a)
- 运行结果为
- 捕获分组:匹配子表达式的结果被暂时保存到内存中,以备表达式或其他程序使用,这个过程就是“捕获”,捕获结果可以通过组编号或组名进行引用。
- 非捕获分组:与上面相反,不想存,不想引用,只是单纯的匹配。
- 实现方法:组开头使用?:
import re s = 'img1.png, img2.png, img3.jpg, img4.png' # 捕获分组,将括号中的内容作为子表达式进行捕获匹配,将组的内容返回 p1 = r'w+(.png)' mlist = re.findall(p1,s) print(mlist) # 非捕获分组,将括号中的内容作为普通正则字符串进行整体匹配,即找到.png结尾的文本 p2 = r'w+(?:.png)' nlist = re.findall(p2,s) print(nlist)
- 运行结果
- re模块是python内置的正则表达式模块。
- 两者非常相似, 区别如下:
- search():在输入字符串中查找,返回第一个匹配内容,找到就匹配对象,没找到就返回None。
- match():在输入字符串开始处查找匹配内容,找到就匹配对象,没找到就返回None。
- 示例
import re p = r'w+@woaipython.com' text = 'my email is coucher42@woaipython.com' # 能匹配 m = re.search(p,text) print(m) # 不能匹配 n = re.match(p,text) print(n) email = 'coucher42@woaipython.com' # 能匹配 a = re.search(p,email) print(a) # 能匹配 b = re.match(p, email) print(b)
- 运行结果
- match对象的几个方法:
email = 'coucher42@woaipython.com' b = re.match(p, email) print(b) print(b.group()) print(b.start()) print(b.span()) print(b.end())
- 运行结果
- 两者相似,区别如下:
- findall():在输入字符串中查找所有匹配内容,如果匹配成功,返回match列表对象,否则返回None。
- finditer():在输入字符串中查找所有匹配内容,如果匹配成功,返回容纳match的可迭代对象,通过迭代对象每次可以返回一个match对象,如果失败则返回None。
import re p = r'[Pp]ython' text = 'i like python or Python.' match_list = re.findall(p, text) print(match_list) match_iter = re.finditer(p, text) for i in match_iter: print(i) print(i.group())
- 运行结果
- 函数split(),按照匹配的子字符串进行分割,返回字符串列表对象。
- 构造方式:re.split(pattern, string, maxsplit=0, flags=0)
- pattern:正则表达式
- string:要分割的字符串
- maxsplit:最大分割次数,默认为0,意味着分割次数没有限制
- flags:编译标志。
import re p = r'd+' text = 'ABCD12EF33gh' clist = re.split(p, text) print(clist) dlist = re.split(p, text, maxsplit=1) print(dlist) elist = re.split(p, text, maxsplit=2) print(elist)
- 运行结果
- 函数sub(),用于替换匹配的字符串,返回值是替换之后的字符串。
- 构造方式:re.sub(pattern, repl, string, count=0, flags=0)
- pattern:正则表达式
- repl:要替换字符串
- string:要提供的字符串
- count:要替换的最大数量,默认为0,意味着替换没有次数
- flags:编译标志
import re p = r'd+' text = 'ABCD12EF33gh' replace_text = re.sub(p, ' ', text) print(replace_text) replace_text = re.sub(p, ' ', text, count=1) print(replace_text) replace_text = re.sub(p, ' ', text, count=2) print(replace_text)
- 运行结果