正则表达式(regular expression,regex,RE)可以用来匹配、检索、分割和替换具有某种特征的字符串,如邮箱、IP 地址、电话号码等,使用方便,效率很高。

特点

  1. 正则表达式能够凝练字符串的特征
  2. 是通用的字符串表达框架
  3. 是简洁表达一组字符串的表达式
  4. 可以判断某个字符串的特征归属,是否具有这个特征

作用

  1. 表达文本类型的特征

  2. 同时查找或替换一组字符串

  3. 匹配字符串的全部或部分

正则表达式由字符和操作符构成,基本和常用的正则表达式操作符如下:

操作符 说明 例子
. 表示任何单个字符
[] 给出单个字符的取值范围 [abc]:a 或 b 或 c,[a-z]:a-z 单个字母
[^] 排除此取值范围 [^abc]:非 a 或 b 或 c
* 前一个字符出现 >=0 abc*:ab、abc、abcc、abccc 等
+ 前一个字符出现 >=1 abc+:abc、abcc、abccc 等
? 前一个字符出现 01 abc?:ab、abc
| 左右表达式中的一个 abc|def:abc、def
{m} 前一个字符出现 m ab{2}c:abbc
{n,} 前一个字符出现 >=n ab{2,}c:abbc、abbbc、abbbbc 等
{m,n} 前一个字符出现 m-n 次(含 n ab{1,3}c:abc、abbc、abbbc
^ 匹配字符串的开头 ^123:字符串以 123 开头
$ 匹配字符串的结尾 123$:字符串以 123 结尾
() 分组标记,内部只能使用 | (abc):abc,(abc|def):abc、def
\d 数字,等价于 [0-9]
\w 单词字符,等价于 [A-Za-z0-9_]
\D 数字除外
\W 数字字母下划线除外
\s 任何空白字符,空格、制表符、换页符等。 等价于 [\f\n\r\t\v]
\S 任何非空白字符 等价于 [^\f\n\r\t\v]
\ 转义字符 \.:普通的 .
*? 惰性匹配上一个 'AbcE123', '[0-9]*?'''
+? 惰性匹配上一个 'AbcE123', '[0-9]+?''1'

经典实例

^[A-Za-z]+$:由字母组成的字符串

^[A-Za-z]+$:由字母和数字组成的字符串

^-?[1-9]\d*$:整数

^[1-9]\d*$:正整数

[\u4e00-\u9fa5]:匹配中文字符

re.compile() 函数

re.compile(pattern, flags=0)

flags:可选,表示匹配模式

  • re.I:忽略大小写
  • re.L:表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
  • re.M:多行模式
  • re.S:使得 . 包括换行符在内的任意字符(. 默认不包括换行符)
  • re.U:表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
  • re.X:为了增加可读性,忽略空格和 # 后面的注释
1
2
3
4
5
import re
string = '112AbCdEf122'
pattern = re.compile('[a-z]+', re.I)
re.search(pattern, string)
<re.Match object; span=(3, 9), match='AbCdEf'>

re.Ire.M 使用较多。

re.match() 函数

re.match(pattern, string, flags=0)

只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,匹配成功时返回 match 对象。

match 对象常用方法:

  • group():返回匹配的字符串
  • start():返回匹配字符串开始的位置
  • end():返回匹配字符串结束的位置
  • span ():返回开始和结束位置
  • groups():返回所有匹配的子串

前 4 个方法默认参数值为 0,可以手动设置为 1、2 等,对应选择出子表达式的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
string = 'abcFGc123'
pattern = re.compile('[a-z]+', re.I)
match = re.match(pattern, string)
match.group()
'abcFGc'
match.start()
0
match.end()
6
match.span()
(0, 6)

string = '11abcFGc123'
match = re.match(pattern, string)
type(match)
<class 'NoneType'> 只匹配字符串开始

re.search() 函数

re.search(pattern, string, flags=0)

re.match() 不同的是,re.search() 匹配整个字符串,直到找到一个匹配。

1
2
3
4
5
6
string = '11abcFGc123'
match = re.search(pattern, string)
type(match)
<class 're.Match'>
match.group()
# 'abcFGc'

re.findall() 函数

re.findall(pattern, string, flags=0)

  • string: 待匹配的字符串
  • pos:可选参数,指定字符串的起始位置,默认为 0
  • endpos:可选参数,指定字符串的结束位置,默认为字符串的长度

以列表形式返回所有匹配的字符串:

1
2
re.findall(r'[0-9]+', '2022年05月05日,阴')
['2022', '05', '05']

re.finditer() 函数

re.finditer(pattern, string, flags=0)

返回含有所有 match 对象的可迭代对象:

1
2
3
4
5
6
7
8
9
import re

temp = '2022年05月05日,阴'
it = re.finditer(r'\d+', temp)
for match in it:
print(match, type(match), match.group())
<re.Match object; span=(0, 4), match='2022'> <class 're.Match'> 2022
<re.Match object; span=(5, 7), match='05'> <class 're.Match'> 05
<re.Match object; span=(8, 10), match='05'> <class 're.Match'> 05

re.sub() 函数

re.sub(pattern, repl, string, count=0, flags=0)

  • pattern:正则中的模式字符串。
  • repl:替换的字符串,也可为一个函数。
  • string:要被查找替换的原始字符串。
  • count:模式匹配后替换的最大次数,默认0 表示替换所有的匹配

匹配字符串并替换:

1
2
re.sub(r'\d+', '某', '2022年05月05日,阴')
'某年某月某日,阴'

练习

  1. "2004-959-559 # 这是一个国外电话号码"(1)去掉#和它之后的内容,(2)只保留数字

    1
    2
    3
    4
    re.sub(r'#+.+', '', '2004-959-559 # 这是一个国外电话号码')
    '2004-959-559 '
    re.sub(r'[^\d]+', '', '2004-959-559 # 这是一个国外电话号码')
    '2004959559'
  2. "aabccaaadaaaa" 中连续的 a 替换成 b,替换后结果为 bbccbdb

    1
    2
    re.sub(r'a+', 'b', 'aabccaaadaaaa')
    'bbccbdb'
  3. "A23G4HFD567",将匹配的数字乘以 2

    1
       

re.split() 函数

re.split(pattern, string, maxsplit=0, flags=0)

  • pattern:正则中的模式字符串
  • string:要分割的字符串
  • maxsplit:可选,分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数
  • flags:可选,表示匹配模式

匹配后分割字符串:

1
2
3
4
re.split(r'\d+', '2022年05月05日,阴')
['', '年', '月', '日,阴']
re.split(r'\d+', '2022年05月05日,阴', maxsplit=1)
['', '年05月05日,阴']