Python基础 - 正则表达式

正则表达式

Posted by 王富杰 on Tuesday, April 29, 2025

一、正则表达式介绍

正则表达式是一种用于匹配、查找、替换文本的强大工具。它通过特定的语法规则,定义字符串的模式,用来匹配指定规则的字符串,从而快速处理复杂的文本操作。正则表达式包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),可以用来描述和匹配字符串的特定模式。

1.1、正则表达式的模式

正则表达式的模式可以包括以下几类:

字面值字符:

按照字面意义进行匹配如字母、数字、空格等,例如匹配字母 "a" 将匹配到文本中的 "a" 字符。

元字符:元字符具有特殊的含义

\d # 匹配数字字符,等价于 [0-9]
\D # 匹配非数字字符,等价于 [^0-9]
\w # 匹配单词字符(字母、数字、下划线),等价于 [a-zA-Z0-9_]
\W # 匹配非单词字符 ,等价于 [^a-zA-Z0-9_]
\s # 匹配空白字符(包括空格、换行符、制表符)
\S # 匹配非空白字符
.  # 匹配任意字符(换行符除外) 示例:a.b 匹配 "aab", "a1b", "a b" 等

边界匹配

^   # 匹配字符串的开头 示例:^abc 匹配以 "abc" 开头的字符串
$   # 匹配字符串的结尾 示例:xyz$ 匹配以 "xyz" 结尾的字符串
\b  # 匹配单词边界    示例:\bcat\b 匹配 "cat" 但不匹配 "category"
\B  # 匹配非单词边界  示例:\Bcat\B 匹配 "scattered" 中的 "cat" 但不匹配单独的 "cat"

字符类

[]       # 匹配括号内的任意一个字符              示例:[aeiou] 匹配任意一个元音字母
[^]      # 匹配除了括号内的字符以外的任意一个字符  示例:[^0-9] 匹配任意非数字字符
-        #  在字符类中表示范围                  示例:[a-z] 匹配任意小写字母

量词

*     # 匹配前面的模式零次或多次              示例:ab*c 匹配 "ac", "abc", "abbc" 等
+     # 匹配前面的模式一次或多次              示例:ab+c 匹配 "abc", "abbc" 但不匹配 "ac"
?     # 匹配前面的模式零次或一次              示例:colou?r 匹配 "color" 和 "colour"
{n}   # 匹配前面的模式恰好 n 次              示例:a{3} 匹配 "aaa"
{n,}  # 匹配前面的模式至少 n 次              示例:a{2,} 匹配 "aa", "aaa" 等
{n,m} # 匹配前面的模式至少 n 次且不超过 m 次   示例:a{2,4} 匹配 "aa", "aaa", "aaaa"

分组和捕获

()    # 用于分组和捕获子表达式    示例:(ab)+ 匹配 "ab", "abab" 等  额外捕获最后一个 "ab" 到分组 $1
(?:)  # 用于分组但不捕获子表达式  示例:(ab)+ 匹配 "ab", "abab" 等   不捕获分组

特殊字符

\   # 转义字符,用于匹配特殊字符本身   示例:\. 匹配实际的点号而不是任意字符
.   # 匹配任意字符(除了换行符)      示例:a.b 匹配 "aab", "a1b", "a b" 等
|   # 用于指定多个模式的选择         示例:cat|dog 匹配 "cat" 或 "dog"

修饰符

i # 忽略大小写            示例:/abc/i 可以匹配 "abc", "Abc", "ABC" 等
g # 全局匹配忽略大小写     示例:在字符串 "ababab" 中,/ab/g 会匹配所有三个 "ab"
m # 多行模式             示例:在多行字符串中,/^abc/m 会匹配每行开头的 "abc"

除了这里介绍的常用的模式外,正则表达式还有一些不常用的模式这里就不再进行介绍,以上已经基本包含日常用到的全部了。

1.2、贪婪匹配与惰性匹配

默认情况下,量词(*, +, ?, {})是贪婪的,会尽可能多地匹配字符。在量词后加?可使其变为非贪婪(懒惰)模式:

*?    # 零次或多次,但尽可能少
+?    # 一次或多次,但尽可能少
??    # 零次或一次,但尽可能少
{n,m} # n到m次,但尽可能少

示例:<div>hello world</div>  <.*?> 匹配HTML标签时不会跨标签匹配,只匹配<div>。但是<.*>会匹配<div>hello world</div>

1.3、运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

\                              转义符
(), (?:), (?=), []	           圆括号和方括号
*, +, ?, {n}, {n,}, {n,m}	   限定符
^, $, \任何元字符、任何字符	   定位点和序列(即:位置和顺序)
|                              替换,"或"操作

如上所示,\的优先级是最高的。

二、re模块

python提供了re模块用来进行正则匹配。这里逐个介绍一下常用的功能:

2.1、re.findall()函数

findall获取所有匹配到的所有值,返回一个列表。

>>> import re
>>> print(re.findall('.+', 'abd\ndef\ng'))   # .匹配任意字符,换行符除外
['abd', 'def', 'g']
>>> print(re.findall('.+', 'abd\ndef\ng', flags=re.DOTALL))  # 加上flags=re.DOTALL后 .就可以匹配所有字符包括换行符
['abd\ndef\ng']

这里重点需要注意下flag参数,re模块还有其他的flag选项,例如 re.M 启用多行模式。 re.S是re.DOTALL的简写,使.可以匹配换行符。re.I忽略大小写。

2.2、re.search()函数

search的用法和findall一模一样,区别是返回值。search只会返回匹配规则的第一个值,返回一个Match对象。

>>> res = re.search('\d{3,4}-\d{7,8}', 'Tel:028-7654321')
>>> print(res)
<re.Match object; span=(4, 15), match='028-7654321'>
>>> print(res.span())
(4, 15)
>>> print(res.group())
028-7654321

如上所示,search函数返回一个macth对象,span()是匹配到的索引位置,通过group()就可以获取到匹配的内容。

2.3、分组与捕获

>>> re.findall('(ab)+', 'ababcdaab')
['ab', 'ab']
>>> re.findall('(?:ab)+', 'ababcdaab')
['abab', 'ab']
>>> res = re.search('(ab)+', 'ababcdaab')
>>> res.group()
'abab'
>>> res.group(1)
'ab'

在python中,正则表达式被小括号括起来的部分认为是一个分组。使用(?:)就可以不进行组的捕获。这里说一下组的捕获过程,(ab)+ 完整匹配是匹配到abab,因为ab被连续匹配了两次,但是捕获组只捕获到最后一次匹配,因此findall和group(1)只返回一个ab。group(0)返回整个正则的匹配结果。

2.4、re.finditer()函数

finditer()函数的功能是匹配所有符合规则的内容,返回一个迭代器, 并且通过迭代器拿到的也是Match对象。

res = re.finditer('(\d{3,4})-(\d{7,8})', 'Tel:028-7654321 Tel:029-97654321')
for m in res:
    print(m.group())

2.4、re.compile()函数

compile()可以传一个正则表达式,返回的是一个正则表达式对象。

res = re.compile('.*')  # 返回一个正则表达式对象。

compile多用于用于一个正则表达式被多次匹配的情况,用正则表达式对象再调用findall,search等函数就不需要再传正则字符串了。

2.5、其他函数

  • re.match它只匹配符合规则的第一个值,但是它只能匹配字符串的开头且只能匹配第一行
  • re.fullmatch是匹配字符串整体。
  • re.sub是将匹配到的内容替换成其他内容。
  • re.split是把匹配到的内容作为分隔符进行拆分。

「真诚赞赏,手留余香」

WangFuJie Blog

真诚赞赏,手留余香

使用微信扫描二维码完成支付