第10集:正则表达式入门(下)
学习目标
通过本集的学习,你将能够:
- 使用字符类简写:\d, \w, \s
- 使用分组与捕获
- 使用锚点:^, $
- 实战识别数字和标识符
- 完成更复杂的正则表达式
10.1 字符类简写
有些字符类很常用,正则表达式给它们提供了简写。
\d:数字(digit)
\d 相当于 [0-9]
正则:\d+
能匹配:
"123" ✓
"456" ✓
"abc" ✗\w:单词字符(word)
\w 相当于 [a-zA-Z0-9_]
(字母、数字、下划线)
正则:\w+
能匹配:
"hello" ✓
"hello123" ✓
"hello_world" ✓
"hello-world" ✗(- 不在 \w 里)\s:空白字符(space)
\s 匹配空白字符:
- 空格
- 制表符 (\t)
- 换行符 (\n)
- 回车符 (\r)
正则:hello\s+world
能匹配:
"hello world" ✓
"hello world" ✓(多个空格)
"hello\tworld" ✓(制表符)
"helloworld" ✗(没有空格)否定版本:\D, \W, \S
\d 匹配数字 → \D 匹配非数字
\w 匹配单词字符 → \W 匹配非单词字符
\s 匹配空白 → \S 匹配非空白例子:
正则:\D+
匹配:"abc", "!@#", 但不匹配"123"10.2 分组与捕获
用圆括号 () 可以分组,并且可以"捕获"匹配的内容。
基本分组
正则:(ab)+
能匹配:
"ab" ✓
"abab" ✓
"ababab" ✓捕获分组
分组匹配的内容可以被提取出来!
import re
text = "我的电话是13812345678"
pattern = r"(\d{3})(\d{4})(\d{4})"
match = re.search(pattern, text)
if match:
print("完整匹配:", match.group(0))
print("第1组:", match.group(1))
print("第2组:", match.group(2))
print("第3组:", match.group(3))
输出:
完整匹配: 13812345678
第1组: 138
第2组: 1234
第3组: 5678例子:提取日期
文本:2024-02-19
正则:(\d{4})-(\d{2})-(\d{2})
捕获结果:
group 1: 2024 (年)
group 2: 02 (月)
group 3: 19 (日)Python 代码:
text = "今天是2024-02-19"
pattern = r"(\d{4})-(\d{2})-(\d{2})"
match = re.search(pattern, text)
if match:
year = match.group(1)
month = match.group(2)
day = match.group(3)
print(f"{month}/{day}/{year}") # 02/19/2024非捕获分组
如果你只想分组,不想捕获,可以用 (?:...)
正则:(?:ab)+
(分组,但不捕获)10.3 锚点
锚点匹配位置,而不是字符。
^:字符串开头
正则:^hello
能匹配:
"hello world" ✓(hello 在开头)
"say hello" ✗(hello 不在开头)$:字符串结尾
正则:hello$
能匹配:
"say hello" ✓(hello 在结尾)
"hello world" ✗(hello 不在结尾)同时用 ^ 和 $:精确匹配整个字符串
正则:^hello$
只能匹配:
"hello" ✓
"hello world" ✗
"say hello" ✗例子:验证完整数字
目标:整个字符串都是数字
正则:^\d+$
能匹配:
"123" ✓
"4567" ✓
"123a" ✗(有字母)
"a123" ✗(有字母)10.4 实战:识别数字和标识符
让我们来实战一下!
任务1:识别整数
目标:识别整数
正则:^-?\d+$
能匹配:
"123" ✓
"-456" ✓
"0" ✓
"+789" ✗(我们没处理加号)
"12.3" ✗(有小数点)任务2:识别浮点数
目标:识别浮点数
分析:
- 可以有小数点
- 小数点前后至少一边有数字
- 可以有负号
正则:^-?(\d+\.\d*|\.\d+|\d+)$
解释:
\d+\.\d* → 123.456, 123.
\.\d+ → .456
\d+ → 123 (整数也是浮点数的一种)
能匹配:
"123" ✓
"123.456" ✓
".456" ✓
"123." ✓
"-123.456" ✓任务3:识别标识符
目标:识别编程语言的标识符
规则:
- 开头:字母或下划线
- 后面:字母、数字、下划线
正则:^[a-zA-Z_][a-zA-Z0-9_]*$
或用简写:
^[a-zA-Z_]\w*$
能匹配:
"hello" ✓
"_world" ✓
"hello123" ✓
"hello_world" ✓
"123hello" ✗(数字开头)
"hello-world" ✗(有减号)10.5 更多例子
例子1:验证邮箱(简化版)
正则:^[\w.-]+@[\w.-]+\.\w+$
能匹配:
"alice@example.com" ✓
"bob.smith@example.co.uk" ✓
"charlie_123@test.org" ✓例子2:验证手机号码(简化版)
假设:11位数字,1开头
正则:^1\d{10}$
能匹配:
"13812345678" ✓
"13987654321" ✓
"1234567890" ✗(不是11位)
"23812345678" ✗(不是1开头)例子3:替换文本
目标:把日期从 yyyy-mm-dd 改成 mm/dd/yyyy
Python 代码:
import re
text = "2024-02-19, 2023-12-31"
pattern = r"(\d{4})-(\d{2})-(\d{2})"
result = re.sub(pattern, r"\2/\3/\1", text)
print(result)
输出:
02/19/2024, 12/31/202310.6 常用正则速查表
字符:
. 任意字符
[abc] a 或 b 或 c
[^abc] 不是 a/b/c 的字符
[a-z] 小写字母
[0-9] 数字
简写:
\d 数字 [0-9]
\w 单词字符 [a-zA-Z0-9_]
\s 空白字符
\D 非数字
\W 非单词字符
\S 非空白
量词:
* 0次或多次
+ 1次或多次
? 0次或1次
{n} 恰好n次
{n,} 至少n次
{n,m} n到m次
锚点:
^ 字符串开头
$ 字符串结尾
分组:
(...) 捕获分组
(?:...) 非捕获分组10.7 在 Python 中常用的 re 函数
import re
# 1. re.search:查找第一个匹配
match = re.search(pattern, text)
if match:
print("找到了")
# 2. re.findall:查找所有匹配
results = re.findall(pattern, text)
print(results)
# 3. re.match:从开头匹配
match = re.match(pattern, text)
# 4. re.sub:替换
new_text = re.sub(pattern, replacement, text)
# 5. re.split:分割
parts = re.split(pattern, text)10.8 自测一下
问题 1
\d 相当于什么?
A) [a-z]
B) [0-9]
C) [a-zA-Z0-9_]
D) 空白字符
问题 2
哪个正则能匹配"hello"并且只匹配"hello"?
A) hello
B) ^hello
C) hello$
D) ^hello$
问题 3
分组用什么括号?
A) [ ]
B) { }
C) ( )
D) < >
答案:
- B
- D
- C
10.9 启蒙篇总结
🎉 恭喜!你已经完成了启蒙篇的学习!
我们学到了:
- 什么是编译器以及为什么需要它
- 计算机是如何执行程序的
- 编程语言的家族树
- 编译器的工作流程
- 历史上的编译器传奇
- 为什么要学习编译原理
- 如何搭建学习环境
- 抽象思维训练
- 正则表达式入门(上)
- 正则表达式入门(下)
你现在已经有了坚实的基础!
10.10 下一篇章预告
下一篇章,我们将进入:编程语言基础篇!
我们会学习:
- Python 快速入门(变量、数据类型、控制流)
- Python 函数、类、文件操作
- 理解编程语言的语法
- 上下文无关文法
- BNF 表示法
- 语言设计原则
- 作用域与绑定
- 类型系统
- 以及更多...
准备好了吗?我们下一篇章见!
参考资料
- Python re 模块官方文档
- regex101.com(在线测试正则表达式)
- 《精通正则表达式》
- 各种正则表达式速查表