正则表达式笔记
Python 正则表达式学习笔记
一、正则表达式是什么
正则表达式(Regular Expression)是一种描述字符串规则的工具,常用于查找、提取、验证和替换文本。例如,从文章中提取数字、检查输入格式、删除多余空格,都可以使用正则表达式。
Python 通过内置的 re 模块使用正则:
1 | |
这里的 \d 表示数字,+ 表示前面的内容出现一次或多次,因此 \d+ 可以匹配连续数字。
正则适合处理具有明确模式的文本。简单的固定内容判断,使用 in、startswith() 或 replace() 往往更直观。
二、为什么通常使用原始字符串
Python 字符串和正则表达式都使用反斜杠,容易产生转义冲突。建议在正则字符串前加 r:
1 | |
r 表示原始字符串,让 Python 保留反斜杠,交给正则引擎解释。
例如,正则中的 \b 表示单词边界,但普通 Python 字符串中的 "\b" 表示退格字符。因此,写正则时通常使用 r"\b"。
需要注意:原始字符串并不是让正则失去转义功能,而是减少 Python 字符串这一层的转义处理。
三、常用字符与字符集合
| 写法 | 含义 | 示例 |
|---|---|---|
. |
默认匹配除换行符外的任意字符 | a.c |
\d |
匹配一个数字字符 | \d\d |
\D |
匹配一个非数字字符 | \D+ |
\w |
匹配 Unicode 字母、数字及下划线 | \w+ |
\W |
匹配不属于 \w 的字符 |
\W+ |
\s |
匹配空白字符,如空格、制表符、换行符 | \s+ |
\S |
匹配非空白字符 | \S+ |
[abc] |
匹配 a、b、c 中的任意一个 | [abc]+ |
[0-9] |
匹配一个 ASCII 数字 | [0-9]+ |
[^abc] |
匹配除 a、b、c 外的任意一个字符 | [^abc]+ |
方括号表示字符集合,每次匹配一个字符。例如 [abc] 可以匹配 "a",但它不表示匹配完整的 "abc"。
在 Python 默认的 Unicode 模式下,\d 不只匹配 0~9,\w 也可以匹配汉字。若要求输入只能包含英文和数字,应明确写出范围:
1 | |
四、数量限定符
数量限定符用于规定前面的字符或分组出现多少次。
| 写法 | 含义 |
|---|---|
* |
零次或多次 |
+ |
一次或多次 |
? |
零次或一次 |
{n} |
恰好 n 次 |
{n,} |
至少 n 次 |
{n,m} |
至少 n 次,最多 m 次 |
例如:
1 | |
-? 表示负号可以出现一次,也可以不出现。因此,最后一个模式能够匹配 "25" 和 "-25"。
限定符只作用于它前面的一个单位:ab+ 表示一个 a 后跟一个或多个 b;(ab)+ 才表示 "ab" 整体重复。
五、位置与边界
^ 表示字符串开头,$ 表示字符串结尾附近的位置。需要注意,$ 也可以匹配字符串末尾换行符之前的位置。
1 | |
\b 表示单词边界,即 \w 与 \W 之间,或相关的字符串起止位置:
1 | |
它适合区分英文单词,但不能直接当作中文分词工具。
如果目标是验证整个字符串,优先使用 re.fullmatch(),这样表达的意图更清楚。
六、Python 中常用的匹配函数
1. re.search():寻找第一个匹配
它会扫描字符串,找到第一个符合规则的内容。成功返回匹配对象,失败返回 None。
1 | |
2. re.match():只从开头匹配
1 | |
从开头匹配成功,并不意味着整个字符串都符合规则。
3. re.fullmatch():匹配整个字符串
1 | |
适合检查用户输入的格式。
4. re.findall():查找所有匹配
1 | |
结果通常是字符串列表;如果模式包含捕获分组,返回结构会发生变化。
5. re.finditer():逐个获取匹配对象
1 | |
group() 获取匹配内容,span() 获取起止位置,结束位置不包含在匹配范围内。
七、分组与“或者”
圆括号可以把多个字符作为一个整体,也可以捕获其中的内容:
1 | |
group(0) 是完整匹配,后面的编号对应各个捕获分组。
如果只需要分组,不需要提取内容,可以使用非捕获分组 (?:...)。
竖线 | 表示“或者”:
1 | |
它可以匹配 "cat" 或 "dog"。给选择范围加上括号,能让模式的结构更明确。
八、贪婪与非贪婪匹配
数量限定符默认采用贪婪匹配:在允许后续模式成功的前提下,尽可能匹配更多内容。
1 | |
在限定符后加 ?,可以改为非贪婪匹配:
1 | |
非贪婪表示优先尝试较短的匹配,仍然需要满足整个模式。复杂 HTML 应使用专门的解析器处理。
九、替换、拆分与常用标志
re.sub() 用于替换符合规则的内容:
1 | |
re.split() 可以按照多个分隔符拆分:
1 | |
常用匹配标志包括:
re.I:忽略大小写。re.M:让^、$也匹配每行的开头、结尾。re.S:让.也能匹配换行符。re.A:让\d、\w等采用 ASCII 范围。
同一个模式需要反复使用时,可以先编译:
1 | |
十、实战思路与常见错误
例如,检查用户名:长度为 4~16 位,以英文字母开头,其余字符只能是英文字母、数字或下划线。
1 | |
首字符已经占了一位,因此后面的长度是 {3,15}。
学习和编写正则时,可以按以下顺序进行:
- 明确要查找、提取、替换还是验证。
- 拆分规则,确定字符范围、数量和位置。
- 先写简单模式,再加入分组或边界。
- 测试正常、错误、空字符串和长度边界情况。
常见错误包括:未判断 None 就调用 group();把 match() 当作完整验证;忘记转义字面量的点号;使用捕获分组后误解 findall() 的返回结果。
要匹配真正的点号,应写 r"\."。要把外部字符串当作普通文本嵌入模式,可以使用 re.escape()。
最后,正则通常负责检查“形式”,业务代码负责检查“含义”。例如,日期模式能确认 "2026-99-99" 的结构,却不能确认日期真实存在;还需要日期解析或额外校验。