正则表达式 - 教程
正则表达式(Regular Expression,简称 regex/regexp)是一种描述文本模式的语言。用一串"模式符号"就能完成搜索、匹配、替换、校验等复杂文本操作,是程序员必备的文本处理利器。
正则能做什么
| 场景 | 示例 |
|---|---|
| 表单校验 | 邮箱、手机号、身份证格式检查 |
| 数据提取 | 从日志中抽取 IP、时间、金额 |
| 批量替换 | 把所有换行符替换为空格 |
| 代码搜索 | 编辑器/IDE 中按模式查找 |
| 日志分析 | 匹配特定错误模式 |
一个直观的例子
模式:^\d{3}-\d{4}-\d{4}$
作用:匹配形如 138-1234-5678 的手机号
\d → 数字
{3} → 恰好 3 个
^ $ → 开头和结尾
各语言都支持
- Python:
re模块 - JavaScript:
RegExp对象 / 字面量 - Java:
java.util.regex - Grep/sed/awk:命令行文本处理
- 数据库:MySQL 的
REGEXP、PostgreSQL 的~
学习建议
- 先掌握基础语法(字符、量词、分组)
- 多用在线工具(regex101.com)边写边看
- 从简单模式开始,逐步叠加
- 避免"一次写对"的执念,分步构建模式
遇到复杂正则先拆解:先匹配局部,再组装完整模式;写完后一定要测边界情况(空字符串、超长文本)。
正则表达式 - 简介
正则表达式是描述字符模式的迷你语言。理解它的基本概念,是掌握所有语法的前提。
什么是"模式"
模式就是一组规则,描述"什么样的文本符合要求"。正则引擎会拿着模式去目标文本中寻找匹配的部分。
模式:cat
文本:The cat sat on the mat.
匹配结果:找到 "cat"(第 5-8 个字符)
字面量 vs 元字符
| 类型 | 说明 | 示例 |
|---|---|---|
| 字面量 | 普通字符,匹配自身 | cat 匹配 "cat" |
| 元字符 | 有特殊含义的符号 | . ^ $ * + ? { } [ ] \ | ( ) |
第一个正则
import re
text = "The price is $99 and $120."
# 匹配所有 $ 开头的数字
pattern = r"\$\d+"
matches = re.findall(pattern, text)
print(matches) # ['$99', '$120']
正则引擎工作方式
- 从文本开头逐字符扫描
- 尝试用模式匹配当前位置
- 匹配成功则记录,继续找下一个
- 匹配失败则向后移动一个字符重试
贪婪与惰性
- 贪婪:默认尽可能多匹配(
.*) - 惰性:加
?后尽可能少匹配(.*?)
匹配元字符本身需要转义:匹配句号用 \.,匹配反斜杠用 \\。
正则表达式 - 语法
正则表达式的基础语法:字符类、量词、分组、锚点等。本节给出最常用的语法速览。
字符匹配
| 语法 | 含义 | 示例匹配 |
|---|---|---|
abc | 精确字符串 | "abc" |
. | 任意单个字符(除换行) | "a.b" 匹配 "axb" |
\d | 数字 | "\d" 匹配 "5" |
\w | 字母数字下划线 | "\w" 匹配 "a" |
\s | 空白符(空格/Tab/换行) | "\s" 匹配 " " |
\D \W \S | 对应取反 | "\D" 匹配非数字 |
字符类 []
[abc] 匹配 a、b、c 之一
[a-z] 匹配小写字母
[0-9] 匹配数字
[a-zA-Z] 匹配所有字母
[^abc] 匹配除 a/b/c 外的字符(^在类内表示取反)
量词
| 语法 | 含义 |
|---|---|
* | 0 次或多次 |
+ | 1 次或多次 |
? | 0 次或 1 次(可选) |
{n} | 恰好 n 次 |
{n,} | 至少 n 次 |
{n,m} | n 到 m 次 |
锚点
| 语法 | 含义 |
|---|---|
^ | 行首 |
$ | 行尾 |
\b | 单词边界 |
分组与或
(abc) 捕获分组
(?:abc) 非捕获分组
a|b 或:a 或 b
\1 反向引用第一个分组
综合示例
import re
# 匹配 2026-08-11 或 2026/08/11 格式的日期
pattern = r"\d{4}[-/]\d{2}[-/]\d{2}"
print(re.findall(pattern, "日期 2026-08-11 和 2026/08/11"))
在 Python 中写正则建议用原始字符串 r"...",避免反斜杠双重转义。
正则表达式 - 修饰符
修饰符(flags)改变正则的整体行为,例如是否区分大小写、是否跨行匹配。
常用修饰符
| 修饰符 | Python | JavaScript | 含义 |
|---|---|---|---|
| 忽略大小写 | re.I | /i | 匹配不区分大小写 |
| 多行模式 | re.M | /m | ^$ 匹配每行首尾 |
| 点匹配换行 | re.S | /s | . 也匹配换行符 |
| 详细模式 | re.X | /x | 忽略空白与注释 |
| 全局匹配 | —(findall 天然全局) | /g | 查找所有匹配 |
Python 示例
import re
text = "Python python PYTHON"
# 默认区分大小写:只匹配一个
print(re.findall(r"python", text)) # ['python']
# 忽略大小写:匹配三个
print(re.findall(r"python", text, re.I)) # ['Python', 'python', 'PYTHON']
多行模式
text = "line1\nline2\nline3"
# 不带 M:^ 只匹配整个文本开头
print(re.findall(r"^line", text)) # ['line']
# 带 M:匹配每行开头
print(re.findall(r"^line", text, re.M)) # ['line', 'line', 'line']
点匹配换行
text = "hello\nworld"
# 默认 . 不匹配换行 → 匹配失败
print(re.findall(r"hello.world", text)) # []
# 带 S:. 匹配换行
print(re.findall(r"hello.world", text, re.S)) # ['hello\nworld']
JavaScript 示例
const text = "Color color COLOUR";
console.log(text.match(/color/gi)); // ['Color', 'color', 'COLOUR']
// g=全局,i=忽略大小写
需要同时用多个修饰符时,Python 用 re.I | re.M 组合;JS 直接连写 /pattern/im。
正则表达式 - 元字符
元字符是正则中具有特殊含义的字符,是构建模式的核心积木。本节分类讲解常用元字符。
字符类元字符
| 元字符 | 含义 |
|---|---|
. | 任意单个字符(默认不含换行) |
\d | 数字 [0-9] |
\D | 非数字 |
\w | 单词字符 [a-zA-Z0-9_] |
\W | 非单词字符 |
\s | 空白符 |
\S | 非空白符 |
锚点元字符
| 元字符 | 含义 |
|---|---|
^ | 行首 |
$ | 行尾 |
\b | 单词边界 |
\B | 非单词边界 |
量词元字符
| 元字符 | 含义 |
|---|---|
* | 0 或多次 |
+ | 1 或多次 |
? | 0 或 1 次 |
{n,m} | n 到 m 次 |
分组与逻辑元字符
| 元字符 | 含义 |
|---|---|
(...) | 分组 |
[...] | 字符类 |
| | 或 |
\\ | 转义 |
实战:提取 IP 地址
import re
log = "访问来自 192.168.1.10 和 10.0.0.1"
pattern = r"\d{1,3}(\.\d{1,3}){3}"
print(re.findall(pattern, log))
# ['192.168.1.10', '10.0.0.1']
实战:匹配邮箱
pattern = r"[\w.-]+@[\w-]+\.[\w.]+"
text = "联系 admin@example.com 或 user@mail.cn"
print(re.findall(pattern, text))
# ['admin@example.com', 'user@mail.cn']
元字符要匹配字面本身时必须转义:\. \* \+ \? \[ 等。
正则表达式 - 运算符优先级
正则表达式的运算符优先级决定了模式的解析顺序。理解优先级,才能正确组合复杂模式。
优先级从高到低
| 优先级 | 运算 | 示例 |
|---|---|---|
| 1(最高) | 转义/字符类 | \d、[abc] |
| 2 | 分组 | (abc) |
| 3 | 量词 | a*、a+、a{2} |
| 4 | 连接(相邻字符) | ab、a.b |
| 5(最低) | 或 | a|b |
经典坑:或的优先级
模式:cat|dog
含义:匹配 "cat" 或 "dog"
模式:cat|dog food
含义:匹配 "cat" 或 "dog food"(| 的优先级低于连接!)
正确写法:(cat|dog) food
含义:匹配 "cat food" 或 "dog food"
量词的作用范围
ab* → a 后面跟 0 个或多个 b(量词只作用于 b)
(ab)* → 0 个或多个 "ab"(分组后整体重复)
[ab]* → 任意个 a 或 b
示例对比
| 模式 | 匹配的文本 |
|---|---|
ab+ | "ab"、"abb"、"abbb"(a 必须 1 个) |
(ab)+ | "ab"、"abab"、"ababab" |
a|ab | "a" 或 "ab" |
a(?:b|c) | "ab" 或 "ac" |
用分组明确优先级
import re
# 想匹配 "error" 或 "warning" 后跟冒号
# ❌ 错误:| 优先级低,会匹配整个 "error|warning:"
pattern1 = r"error|warning:"
# ✅ 正确:分组提升优先级
pattern2 = r"(?:error|warning):"
print(re.findall(pattern2, "error: 出现了 warning:"))
# ['error:', 'warning:']
拿不准优先级时,用括号显式分组最保险,也让模式更易读。
正则表达式 - 匹配规则
本节讲解正则的匹配规则:贪婪与惰性、匹配过程,以及如何避免常见的匹配陷阱。
贪婪匹配(默认)
量词默认贪婪:尽可能多地匹配字符。
import re
text = "<a>链接1</a> 和 <a>链接2</a>"
# 贪婪:.* 一直吃到最后一个 </a>
print(re.findall(r"<a>.*</a>", text))
# ['<a>链接1</a> 和 <a>链接2</a>']
惰性匹配
量词后加 ? 变为惰性:尽可能少地匹配。
# 惰性:.*? 匹配到第一个 </a> 就停
print(re.findall(r"<a>.*?</a>", text))
# ['<a>链接1</a>', '<a>链接2</a>']
贪婪 vs 惰性对照
| 写法 | 行为 |
|---|---|
.* | 贪婪,匹配到不能再多 |
.*? | 惰性,匹配到不能再少 |
.+ | 贪婪,至少 1 个 |
.+? | 惰性,至少 1 个 |
a{2,5} | 贪婪,优先 5 个 |
a{2,5}? | 惰性,优先 2 个 |
匹配过程:回溯
正则引擎在匹配过程中会回溯:贪婪匹配先多吞字符,失败后再逐步吐出重试。复杂的模式 + 长文本可能引发严重的性能问题(灾难性回溯)。
# 危险模式示例:(a+)+ 对长串 aaaaa...X 会指数级回溯
# 避免嵌套量词,必要时用原子分组/占用量词
匹配原则
- 默认贪婪,需要时加
?变惰性 - 匹配 HTML 等结构用惰性(
.*?)更安全 - 避免嵌套量词(如
(a+)+、(.*)*)
处理 HTML/JSON 等结构化文本时,优先用专门解析器,正则只做简单模式提取。
正则表达式 - 位置匹配
位置匹配不消耗字符,只断言"位置"满足条件。锚点(^ $ \b)和环视(lookaround)都属于位置匹配。
行首行尾
import re
text = "hello world\nhello python"
# 匹配行首的 hello
print(re.findall(r"^hello", text, re.M)) # ['hello', 'hello']
# 匹配行尾的 world / python
print(re.findall(r"\w+$", text, re.M)) # ['world', 'python']
单词边界 \b
\b 匹配单词与非单词字符之间的位置。
text = "cat catalog scatter cat"
# 只匹配独立的 "cat"
print(re.findall(r"\bcat\b", text)) # ['cat', 'cat']
# 不匹配 catalog(cat 后不是边界)和 scatter(cat 前不是边界)
非单词边界 \B
# \Bcat\B 匹配单词中间的 cat
print(re.findall(r"\Bcat\B", "catalog")) # ['cat']
实战:验证以 .md 结尾
files = ["readme.md", "notes.txt", "guide.md"]
md = [f for f in files if re.search(r"\.md$", f)]
print(md) # ['readme.md', 'guide.md']
锚点与 findall 的配合
text = "123-456-7890"
# 匹配整个字符串是一个电话号码(^...$)
pattern = r"^\d{3}-\d{3}-\d{4}$"
print(bool(re.match(pattern, text))) # True
校验类正则(邮箱、手机号、URL)务必加 ^ 和 $ 锚定首尾,否则可能只匹配到部分内容却判为合法。
正则表达式 - 分组和引用
分组把模式的一部分"打包",可以整体重复、捕获内容、反向引用。是构建复杂正则的必备技能。
捕获分组 ()
import re
text = "2026-08-11"
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", text)
print(m.group(0)) # 2026-08-11(整体)
print(m.group(1)) # 2026
print(m.group(2)) # 08
print(m.group(3)) # 11
分组与 findall
# 有分组时 findall 返回分组元组
print(re.findall(r"(\d{4})-(\d{2})", "2026-08 和 2025-01"))
# [('2026', '08'), ('2025', '01')]
非捕获分组 (?:...)
只需要分组重复、不需要捕获内容时用 (?:...),性能更好:
# (?:ab)+ 整体重复但不捕获
print(re.findall(r"(?:ab)+", "abab ab")) # ['abab', 'ab']
反向引用 \1
在模式中引用前面分组捕获的内容:
# 匹配重复单词:"the the"
text = "the the cat"
print(re.search(r"(\w+) \1", text).group(0)) # the the
# 匹配成对标签:<b>内容</b>
html = "<b>加粗</b> 和 <i>斜体</i>"
pattern = r"<(\w+)>.*?</\1>"
print(re.findall(pattern, html)) # ['b', 'i']
命名分组(Python)
m = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})", "2026-08")
print(m.group("year")) # 2026
print(m.group("month")) # 08
JavaScript 分组
const m = "2026-08-11".match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(m[1], m[2], m[3]); // 2026 08 11
捕获分组越多,模式越难读。能用 (?:...) 就不捕获;只关心整体时优先用 findall 加非捕获分组。
正则表达式 -选择和分支
选择与分支用 | 表达"或"关系,配合分组可以构造多选一模式。
基本或运算
import re
# 匹配 apple 或 banana
print(re.findall(r"apple|banana", "I like apple and banana"))
# ['apple', 'banana']
分组 + 或
# 匹配 get/post/put/delete 之一
pattern = r"\b(?:get|post|put|delete)\b"
print(re.findall(pattern, "Use GET to fetch, POST to create"))
# ['GET', 'POST'](大小写敏感,用 re.I 可忽略)
字符类 vs 或
| 写法 | 匹配 | 适用 |
|---|---|---|
[abc] | 单个字符 a/b/c | 单字符选择 |
a|b|c | 模式 a 或 b 或 c | 多字符/模式选择 |
(?:ab|cd) | "ab" 或 "cd" | 组合模式选择 |
选择顺序影响结果
# 正则引擎按从左到右尝试分支,先匹配到的优先
text = "cat"
# 都能匹配 "cat"
print(re.findall(r"cat|catalog", text)) # ['cat']
print(re.findall(r"catalog|cat", text)) # ['cat'](cat 在 catalog 之前先试也中)
实战:匹配多种日期格式
text = "2026-08-11, 2026/08/11, 2026.08.11"
pattern = r"\d{4}[-/. ]\d{1,2}[-/. ]\d{1,2}"
print(re.findall(pattern, text))
# ['2026-08-11', '2026/08/11', '2026.08.11']
实战:匹配 HTTP/HTTPS/FTP 链接
text = "访问 https://a.com 或 ftp://b.org"
pattern = r"\b(?:https?|ftp)://[\w.-]+"
print(re.findall(pattern, text))
# ['https://a.com', 'ftp://b.org']
分支模式较长时,把更具体的分支放前面,避免被通用分支抢先匹配。
正则表达式 - 断言
断言(lookaround,环视)只检查位置前后的内容,不消费字符,用于"前方/后方必须是什么,但不把它算进匹配"。
四种断言
| 类型 | 语法 | 含义 |
|---|---|---|
| 正向先行 | (?=...) | 后面必须跟 ... |
| 负向先行 | (?!...) | 后面不能跟 ... |
| 正向后行 | (?<=...) | 前面必须是 ... |
| 负向后行 | (?<!...) | 前面不能是 ... |
正向先行 (?=...)
import re
# 匹配后面跟 "px" 的数字(不把 px 算进结果)
text = "宽度 100px,间距 20em"
print(re.findall(r"\d+(?=px)", text)) # ['100']
负向先行 (?!...)
# 匹配后面不跟字母的数字
text = "版本 3 和 3x 版本"
print(re.findall(r"\d+(?!x)", text)) # ['3'](3x 里的 3 被排除)
正向后行 (?<=...)
# 匹配 $ 符号后面的金额
text = "价格 $99 和 ¥120"
print(re.findall(r"(?<=\$)\d+", text)) # ['99']
负向后行 (?<!...)
# 匹配前面不是 # 的单词 color
text = "#color 和 color"
print(re.findall(r"(?
断言与捕获的区别
# 捕获(\d+ 包括在内)
print(re.findall(r"(\d+)px", "宽 100px")) # ['100']
# 断言(\d+ 本身,px 只是条件)
print(re.findall(r"\d+(?=px)", "宽 100px")) # ['100']
# 看似一样,但断言不消费 px,可继续匹配
print(re.findall(r"\d+(?=px).", "宽 100px")) # ['100p']
后行断言 (?<=...) 要求固定长度,Python 中长度可变的后行(如 (?<=\d+))会报错;先行断言无此限制。
正则表达式 - 示例
本节通过高频实战示例,展示正则在各场景的具体用法。
1. 手机号校验
import re
def is_phone(s):
return bool(re.fullmatch(r"1[3-9]\d{9}", s))
print(is_phone("13812345678")) # True
print(is_phone("12812345678")) # False(第二位必须是 3-9)
2. 邮箱提取
text = "联系 zhangsan@example.com 或 lisi@mail.org"
emails = re.findall(r"[\w.-]+@[\w-]+\.[\w.]+", text)
print(emails)
# ['zhangsan@example.com', 'lisi@mail.org']
3. 从日志提取时间
log = "2026-08-11 10:30:45 INFO 请求成功"
time = re.search(r"\d{2}:\d{2}:\d{2}", log)
print(time.group(0)) # 10:30:45
4. 提取 URL
text = "参考 https://docs.python.org/3/ 和 https://regex101.com"
urls = re.findall(r"https?://[\w./-]+", text)
print(urls)
# ['https://docs.python.org/3/', 'https://regex101.com']
5. 提取 HTML 标签内容
html = "<p>段落一</p><p>段落二</p>"
paras = re.findall(r"<p>(.*?)</p>", html)
print(paras) # ['段落一', '段落二']
6. 数据清洗:去空白
text = " 你好, 世界 "
clean = re.sub(r"\s+", " ", text).strip()
print(repr(clean)) # '你好, 世界'
7. 密码强度校验
# 至少 8 位,含大小写字母和数字
pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$"
print(bool(re.fullmatch(pattern, "Abc12345"))) # True
print(bool(re.fullmatch(pattern, "abc12345"))) # False(无大写)
实战中先跑通小样例,再验证边界(空串、超长、特殊字符),最后应用到生产代码。
正则表达式 - 使用总结
总结正则的使用要点、常见陷阱和性能建议,帮你写出健壮高效的正则。
使用流程图
- 明确需求:是校验、提取、替换还是分割?
- 拆解模式:先写核心部分,再逐步完善
- 在线验证:regex101 等工具边写边测
- 测试边界:空串、超长文本、特殊字符
- 性能检查:避免嵌套量词、长回溯
常见陷阱
| 陷阱 | 说明 | 对策 |
|---|---|---|
| 忘记转义 | . * + ? 是元字符 | 匹配字面量时加 \ |
| 锚点缺失 | 校验时只匹配部分 | 用 ^...$ 或 fullmatch |
| 贪婪过度 | .* 匹配过多 | 需要时用 .*? |
| 嵌套量词 | (a+)+ 灾难回溯 | 避免,拆分模式 |
| 分支顺序 | 通用分支抢先 | 具体分支放前面 |
性能建议
- 尽量用字符类
[0-9]而非|分支 - 长文本匹配避免
.*大范围扫描 - 编译正则复用:Python
re.compile() - 大文件处理用流式/按行匹配
各语言使用速查
import re
re.match(pattern, text) # 从开头匹配
re.search(pattern, text) # 搜索任意位置
re.findall(pattern, text) # 返回所有匹配
re.sub(pattern, repl, text) # 替换
text.match(/pattern/g) // 返回数组
text.search(/pattern/) // 返回索引
text.replace(/pattern/g, r) // 替换
/pattern/.test(text) // 布尔判断
grep -E 'pattern' file.txt # 搜索
sed -E 's/pattern/repl/g' f # 替换
awk '/pattern/{print $1}' f # 处理
何时不用正则
- 解析 HTML/XML → 用 BeautifulSoup、cheerio
- 解析 JSON → 用 JSON 解析器
- 复杂嵌套结构 → 用专门语法解析器
"正则解决不了的问题用两个正则"——保持模式简单,比追求一蹴而就更重要。
正则表达式 - 测验
本章测验检验你对正则表达式的掌握。先独立作答,再看解析。
选择题
1. 哪个正则匹配"一个数字"?
- A.
\d✅ - B.
\w - C.
\s - D.
.
2. a+ 匹配什么?
- A. 恰好一个 a
- B. 一个或多个 a ✅
- C. 零个或多个 a
- D. 可选的一个 a
3. 匹配 4 位数字用哪个?
- A.
\d4 - B.
\d{4}✅ - C.
4\d - D.
\d+4
4. ^ 在正则中的作用?
- A. 匹配行尾
- B. 匹配行首 ✅
- C. 转义
- D. 或运算
5. 匹配 "cat" 或 "dog" 的正确写法?
- A.
cat dog - B.
cat|dog✅ - C.
cat,dog - D.
cat+dog
6. 惰性匹配的写法是?
- A.
.* - B.
.*?✅ - C.
.+ - D.
.?
判断题
7. .\d 会匹配 "5a" 中的 "5a"。
❌ 错误。. 匹配任意字符 + \d 匹配数字,"5a" 中 a 不是数字,不匹配。
8. 正则 \bword\b 能匹配 "keyword" 中的 "word"。
❌ 错误。"keyword" 中 word 前面是字母 k,不是单词边界。
简答题
9. 写出匹配"以 http 或 https 开头"的正则。
^https?://
10. 写出匹配邮箱的正则(简单版)。
[\w.-]+@[\w-]+\.[\w.]+
计分
| 答对 | 水平 |
|---|---|
| 9-10 | 优秀,可熟练用于生产 |
| 6-8 | 良好,加强练习 |
| <6 | 建议重学语法与量词章节 |
正则要"常用常新",建议收藏 regex101.com 的参考手册,需要时随时查阅。
正则表达式 – 简介
本节补充正则在更多语言与工具中的用法(与第 1 节简介互补的进阶内容)。
Java 中使用正则
import java.util.regex.*;
String text = "hello123world456";
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(text);
while (m.find()) {
System.out.println(m.group()); // 123, 456
}
Go 中使用正则
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`\d+`)
nums := re.FindAllString("a1b22c333", -1)
fmt.Println(nums) // [1 22 333]
}
MySQL 中使用正则
-- REGEXP:匹配数字开头
SELECT * FROM users WHERE phone REGEXP '^1[3-9]';
-- 匹配包含数字的邮箱
SELECT email FROM users WHERE email REGEXP '[0-9]+@';
命令行使用
# grep 搜索 IP
grep -E '\b(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.|$)' access.log
# sed 替换(把日期格式换掉)
sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/g' file.txt
VS Code 中使用
打开查找框(Cmd/Ctrl + F)→ 点击 .* 图标开启正则
查找:\b\w+@\w+\.\w+\b 提取所有邮箱
替换:$1 引用捕获分组
正则学习资源
| 工具/资源 | 用途 |
|---|---|
| regex101.com | 在线调试(支持 Python/JS/Java 等) |
| regexr.com | 可视化学习 |
| MDN RegExp 文档 | JavaScript 正则权威参考 |
| learn-regex 项目 | GitHub 上的入门教程 |
正则语法在不同语言中 90% 通用,差异主要在修饰符命名和部分高级特性,切换语言时注意查阅差异。
正则表达式
本节作为正则教程的总结与补充,汇总最常用的"即查即用"模式清单。
常用模式速查
| 需求 | 正则 |
|---|---|
| 手机号(大陆) | 1[3-9]\d{9} |
| 邮箱 | [\w.-]+@[\w-]+\.[\w.]+ |
| IP 地址 | (?:\d{1,3}\.){3}\d{1,3} |
| URL | https?://[\w./-]+ |
| 日期 yyyy-mm-dd | \d{4}-\d{2}-\d{2} |
| 时间 HH:MM:SS | \d{2}:\d{2}:\d{2} |
| 纯数字 | ^\d+$ |
| 字母开头 | ^[a-zA-Z] |
| 下划线命名 | ^[a-z_]+(?:[a-z0-9_]*)$ |
| 中文字符 | [\u4e00-\u9fa5] |
| HTML 注释 | <!--.*?--> |
| 空白行 | ^\s*$ |
手机号精确校验(含段位)
import re
p = r"^1(?:3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$"
print(bool(re.fullmatch(p, "13812345678"))) # True
身份证号(18 位,简版)
p = r"^\d{17}[\dXx]$"
print(bool(re.fullmatch(p, "110101199003071234"))) # True
金额格式(千分位)
text = "总价 1,234,567.89 元"
m = re.search(r"\d{1,3}(?:,\d{3})*(?:\.\d+)?", text)
print(m.group(0)) # 1,234,567.89
继续学习建议
- 把本页模式收藏为"个人速查表"
- 遇到新需求先在 regex101 上验证
- 逐步积累自己的模式库(团队复用)
- 关注高级主题:原子分组、回溯控制、Unicode 属性
正则模式会随业务变化,建议为常用模式编写单元测试,防止误伤正常数据。