re
re
是最常用的标准库之一,它为python提供了一个正则表达式(Regular Expression)引擎。
什么是正则表达式
Regular Expression,或者简写为Regex、regexp等。
维基百科
正则表达式,又称规律表达式、正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学概念,用简单字符串来描述、匹配文中全部匹配指定格式的字符串,现在很多文本编辑器都支持用正则表达式搜索、取代匹配指定格式的字符串。
各类主流的编程语言都有正则表达式的支持(然而C和C++的标准库不支持正则表达式)。当然不同编程语言的实现可能有所不同,我们下面只介绍python的re
库。
举个例子
先来看一个例子体会一下正则表达式的用法,如果我有下面的一列字符串:
我想把他们转化成标准化的月薪,应该怎么做呢?FYI
2.5-3.5万·15薪
指的是每个月2.5到3.5万,每年发15个月的工资(可能以奖金的形式发放)。
如果使用正则表达式,我们可以这样写:
后续再对这些匹配的结果进行数值化处理即可。
不难发现这里面最奇怪的一行就是r'(\d+\.?\d*)([万千百]?)-(\d+\.?\d*)([万千百]?)·?(\d*)薪?'
。
实际上这就是所谓的正则表达式,他描述了我们想要搜索的字符模式。
具体来说:
\d
代表0-9的数字+
代表它前面的内容至少一个?
代表它前面的内容0或1个*
代表它前面的内容不限个数[万千百]
代表万、千、百当中的一个()
表示我们想提取括号内的内容
这样一来
(\d+\.?\d*)
的意思就是,我们要匹配并且提取【至少一个数字开头的,可能有小数部分的一个数字】。([万千百]?)
的意思就是,我们要匹配并且提取【可能存在的万、千、百当中的一个】
匹配的结果可视化大概是这样的:
这里也推荐一下图里这个网站:regex101.com可以很方便地调试各种编程语言的正则表达式。
更加全面的规则
上面的例子展示的正则表达式的威力,我们接下来更加细致地讲解正则表达式的规则。
我有一张图,来源不明但我常常拿出来看:
这张图虽然不够全面,但大体上是够用的。
re库的__doc__
里也给出了很详细的说明文档,我这里做一个翻译。
原文
python 3.10.9的re.__doc__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
|
我的翻译
re的手册
本模块提供了和Perl
(另外一个编程语言)类似的正则表达式的匹配操作。同时支持8bit和unicode字符。匹配模式(pattern,也就是正则表达式)和被处理的字符串都可以包含空字节或者ASCII码之外的字符。
正则表达式可以包含特殊的保留字
和其他的普通字符。像是“A”、“a”或者“0”这种普通的字符本身就是最简单的正则表达式,它们的匹配结果就是自身。你可以把普通字符串起来使用,例如'last'
就会匹配'last'
。
re中的保留字列举如下:
保留字 | 功能 |
---|---|
. | 匹配除去换行(\n )的任何字符 |
^ | 匹配字符的开头 |
$ | 匹配字符的结尾 |
* | 匹配任意长度的字符(贪婪地, 有多少匹配多少) |
+ | 匹配一个或者更多的字符(贪婪地) |
? | 匹配零个或者一个字符(贪婪地) |
{m,n} | 匹配m到n个字符,例如2-5个 |
*?, +?, ??, {m,n}? | 前面四个的懒惰模式(尽可能少地匹配) |
\\ 1 | 转义字符, 或者是逃逸字符. 例如\\n 就是转义字符, 匹配一个换行而不是n . \\. 就是逃逸字符, 匹配一个英文句号. , 而不是前面所说的任意字符. |
[...] | 匹配一组字符, 在方括号内用^ 符号作为第一个字符则是匹配这组字符之外的字符. |
| | 或连接符, A|B 会匹配A或者B |
(...) | 匹配括号内的字符, 这些子字符后续可以被检索或者进一步匹配 |
(?aiLmsux) | 设定后面定义的几种匹配模式 |
(?:...) | 和普通的括号类似, 但是不会把括号内匹配的子字符串作为一个组(group) |
(?P<name>...) | 把匹配的子字符串组命名为name |
(?P=name...) | 匹配名称为name 的组 |
(?#...) | 注释 |
(?=...) | 前视断言 |
(?!...) | 否定型前视断言 |
(?<=...) | 后视断言 |
(?>=...) | 否定型后视断言 |
(?(id/name)yes-pattern|no-pattern) | 如果id或者name存在, 尝试匹配yes表达式, 否则匹配no表达式 |
匹配模式(flags)列举如下:
flag | 全称 | 涵义 |
---|---|---|
A | ASCII | 使用ASCII字符集 |
I | IGNORECASE | 不区分大小写 |
L | LOCALE | 没看懂, 估计用处不大. 👉官网的中文解释 |
M | MULTILINE | 多行模式, 待处理的字符串有多行, 这个模式下^$ 标记的是行头行尾而不是字符串的首尾. |
S | DOTALL | . 匹配包括换行在内的所有字符(dot match all) |
X | VERBOSE | 忽视正则表达式中的空白和# 之后的内容 |
U | UNICODE | 使用Unicode字符集 |
re中的转义字符1列举如下:
转义字符 | 涵义 |
---|---|
\number | 指代之前的某个组, 例如(\d+) \1 , 实际上等同于(\d+) (\d+) . 可以匹配, 223 223 . |
\A | 只匹配字符串开头 |
\Z | 只匹配字符串结尾 |
\b | 匹配开头或是结尾的空字符2 |
\B | 匹配不在开头或是结尾的空字符 |
\d | 匹配数字, 在ASCII模式下, 等价于[0-9] . 但非ASCII模式下则是整个Unicode数字集. |
\D | 匹配\d 的补集, 等价于[^\d] |
\s | 匹配空白字符, ASCII模式下等价于[\t\n\r\f\v] . |
\S | 匹配\s 的补集 |
\w | 匹配英文字母和数字, ASCII模式下等价于[a-zA-Z0-9] |
\W | 匹配\w 的补集 |
\\ | 匹配反斜杠 |
规则太复杂了, 再看点例子
我会写一些正则表达式,配上相应的例子。截图中也会包含相应的解释!
VERBOSE模式:(?x)a pple#match apple
不分组匹配:(?:\d+-\d+)
条件匹配:^(<)?(\w+@\w+(?:\.\w+)+)(?(1)>$|$)
条件匹配:(?(1)>$|$)
,这里的条件是第一个匹配分组:(<)
,如果它匹配成功了上面这个条件匹配就会匹配>$
,否则就是$
。
这样一来就可以匹配<xx@xx.xx>
或者是xx@xx.xx
了:
前视断言:\w+(?=@gmail\.com)
分组命名:(?:(?P<mainland>\+86)|(?P<taiwan>\+886)) (?(mainland)\d{11}|\d{10})
re库的api
到这里,你大概已经知道正则表达式怎么写了。借助在线调试网站regex101.com我们可以很方便地查看匹配的情况。
接下来就可以使用各种api来进行正则匹配了。
主要的几个api如下:
match
:从开头匹配一个字符fullmatch
:从头到尾匹配search
:在字符中搜索要匹配的正则表达式(不从头开始)sub
:把匹配的结果替换成指定字符subn
:把匹配的结果替换成指定字符,同时返回替换的个数split
:按照匹配的结果把字符串切割为列表findall
:把所有匹配的结果列举出来,返回一个列表finditer
:效果同上,但是返回一个迭代器compile
:把一个正则表达式字符串编译为Pattern object
purge
:清除缓存escape
:取消字符串中的转义
两个主要的对象:
Pattern
:正则表达式对象Match
:匹配的结果