正则表达式

正则表达式

⭐清晰易懂版

单字符匹配

字符功能
.匹配任意 1 个字符(除了\n)
[ ]匹配 [ ] 中列举的字符
\d匹配数字,即 0-9
\D匹配非数字,即不是数字
\s匹配空白,即 空格,tab 键
\S匹配非空白
\w匹配单词字符,即 a-z、A-Z、0-9、_
\W匹配非单词字符

匹配多个字符的相关格式

字符功能
*匹配前一个字符出现 0 次或者无限次,即可有可无
+匹配前一个字符出现 1 次或者无限次,即至少有 1 次
?匹配前一个字符出现 1 次或者 0 次,即要么有 1 次,要么没有
{m}匹配前一个字符出现 m 次
{m,n}匹配前一个字符出现从 m 到 n 次

概念

正则表达式 (regular expression) 描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等

符号

普通字符

普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号

字符描述
[ABC]匹配 […] 中的所有字符,例如 [aeiou] 匹配字符串 “google runoob taobao” 中所有的 e o u a 字母。 https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206192920315.png
[^ABC]匹配除了 […] 中字符的所有字符,例如 [^aeiou] 匹配字符串 “google runoob taobao” 中除了 e o u a 字母的所有字母 https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206193003594.png
[A-Z][A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母 https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206192825611.png
.匹配除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r] https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206193042154.png
[\s\S]匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,包括换行。 https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206193101636.png
\w匹配字母、数字、下划线。等价于 [A-Za-z0-9_] https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206193134832.png

非打印字符

字符描述
\cx匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f匹配一个换页符。等价于 \x0c 和 \cL。
\n匹配一个换行符。等价于 \x0a 和 \cJ。
\r匹配一个回车符。等价于 \x0d 和 \cM。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t匹配一个制表符。等价于 \x09 和 \cI。
\v匹配一个垂直制表符。等价于 \x0b 和 \cK。

特殊字符

许多元字符要求在试图匹配它们时特别对待。若要匹配这些特殊字符,必须首先使字符 " 转义 “,即,将反斜杠字符**\** 放在它们前面

特别字符描述
$匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。
( )标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。
*匹配前面的子表达式零次或多次。
+匹配前面的子表达式一次或多次。
.匹配除换行符 \n 之外的任何单字符。
[标记一个中括号表达式的开始。
?匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。
\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ’n’ 匹配字符 ’n’。’\n’ 匹配换行符。序列 ‘\’ 匹配 “",而 ‘(’ 则匹配 “("。
^匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。
{标记限定符表达式的开始。
|指明两项之间的一个选择。

限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 ***** 或 +?{n}{n,}{n,m} 共 6 种

字符描述
*匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
+匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
?匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等价于 {0,1}。
{n}n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,}n 是一个非负整数。至少匹配 n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。
{n,m}m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。

定位符

定位符用来描述字符串或单词的边界,^$ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界

字符描述
^匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\b匹配一个单词边界,即字与空格间的位置。
\B非单词边界匹配。

注意

  1. 不能将限定符与定位符一起使用。由于在紧靠换行或者单词边界的前面或后面不能有一个以上位置,因此不允许诸如 ^* 之类的表达式。
  2. 若要匹配一行文本开始处的文本,请在正则表达式的开始使用 ^ 字符。不要将 ^ 的这种用法与中括号表达式内的用法混淆。
  3. 若要匹配一行文本的结束处的文本,请在正则表达式的结束处使用 $ 字符。
  4. \b 字符的位置是非常重要的。如果它位于要匹配的字符串的开始,它在单词的开始处查找匹配项。如果它位于字符串的结尾,它在单词的结尾处查找匹配项
  5. 对于 \B 非单词边界运算符,位置并不重要,因为匹配不关心究竟是单词的开头还是结尾

选择

用圆括号 () 将所有选择项括起来,相邻的选择项之间用 | 分隔。

() 表示捕获分组,() 会把每个分组里的匹配的值保存起来, 多个匹配值可以通过数字 n 来查看 (n 是一个数字,表示第 n 个捕获组的内容)

re 常用方法

match()

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

match() 尝试从字符串的起始位置匹配正则表达式,若匹配,就返回匹配成功的结果;若不匹配,返回 None

1
2
3
4
5
6
7
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match("^Hello\s\d\d\d\s\d{4}\s\w{10}", content)
print(result)
print(result.group())
print(result.span())

输出

1
2
3
4
41
<_sre.SRE_Match object; span=(0, 25), match='Hello 123 4567 World_This'>
Hello 123 4567 World_This
(0, 25)

步骤

  1. match() 方法中,第一个参数传入了正则表达式,第二个参数传入了要匹配的字符串

  2. group() 方法可以输出匹配到的内容,结果是 Hello 123 4567 World_This

    span() 方法可以输出匹配的范围,结果是 (0, 25)

也可这样写

1
result = re.match('^Hello.*Demo$', content)

group()

使用 () 括号将想提取的子字符串括起来

1
2
3
4
5
6
7
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

输出

1
2
3
4
<_sre.SRE_Match object; span=(0, 19), match='Hello 1234567 World'>
Hello 1234567 World
1234567
(0, 19)

若想把字符串中的 1234567 提取出来,此时可以将数字部分的正则表达式用 () 括起来,然后调用了 group(1) 获取匹配结果

也可这样写

1
result = re.match('^He.*?(\d+).*Demo$', content)

匹配对象的方法

  • start([group])
    • 获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引)
  • end([group])
    • 获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引 +1)
  • group()
    • group()group(0) 返回匹配正则表达式整体结果(字符串)
    • group(n) 列出第 n 个括号匹配部分
  • span([group])
    • 返回 (start(group), end(group))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

>>> import re
>>> pattern = re.compile(r'\d+')   
m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
>>> print m                                         # 返回一个 Match 对象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0)   # 可省略 0
'12'
>>> m.start(0)   # 可省略 0
3
>>> m.end(0)     # 可省略 0
5
>>> m.span(0)    # 可省略 0
(3, 5)

修饰符

遇到换行符时,使用修饰符 re.S 进行匹配,即可用“.”匹配换行符

1
result = re.match('^He.*?(\d+).*?Demo$', content, re.S)

其他常用修饰符

https://trou.oss-cn-shanghai.aliyuncs.com/img/image-20201206194553409.png

match() 方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了

search(),它在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果,搜索完了还没有找到,就返回 None

为了匹配方便,尽量使用 search() 方法

findall()

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

注意**:** match 和 search 是匹配一次;findall 匹配所有。

sub()

替换指定文本

如要将文本中的数字去掉

1
2
3
4
import re
content = '54aK54yr5oiR54ix5L2g'
content = re.sub('\d+', '', content)
print(content)

输出

1
aKyroiRixLg

只需要给第一个参数传入 \d+ 来匹配所有的数字,第二个参数为替换成的字符串(如果去掉该参数的话,可以赋值为空),第三个参数是原字符串

compile()

编译正则表达式,生成一个正则表达式 (Pattern) 对象,供 match()search() 使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import re
content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
# or
result3 = pattern.sub('',content3)
print(result1, result2, result3)

输出

1
2016-12-15  2016-12-17  2016-12-22

例如,这里有 3 个日期,我们想分别将 3 个日期中的时间去掉,这时可以借助 sub() 方法。该方法的第一个参数是正则表达式,但是这里没有必要重复写 3 个同样的正则表达式,此时可以借助 compile() 方法将正则表达式编译成一个正则表达式对象,以便复用

split()

escape()

常用模板