正则表达式 - 教程

正则表达式(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 的 ~

学习建议

  1. 先掌握基础语法(字符、量词、分组)
  2. 多用在线工具(regex101.com)边写边看
  3. 从简单模式开始,逐步叠加
  4. 避免"一次写对"的执念,分步构建模式
💡 提示

遇到复杂正则先拆解:先匹配局部,再组装完整模式;写完后一定要测边界情况(空字符串、超长文本)。

正则表达式 - 简介

正则表达式是描述字符模式的迷你语言。理解它的基本概念,是掌握所有语法的前提。

什么是"模式"

模式就是一组规则,描述"什么样的文本符合要求"。正则引擎会拿着模式去目标文本中寻找匹配的部分。

模式: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']

正则引擎工作方式

  1. 从文本开头逐字符扫描
  2. 尝试用模式匹配当前位置
  3. 匹配成功则记录,继续找下一个
  4. 匹配失败则向后移动一个字符重试

贪婪与惰性

  • 贪婪:默认尽可能多匹配(.*)
  • 惰性:加 ? 后尽可能少匹配(.*?)
💡 提示

匹配元字符本身需要转义:匹配句号用 \.,匹配反斜杠用 \\。

正则表达式 - 语法

正则表达式的基础语法:字符类、量词、分组、锚点等。本节给出最常用的语法速览。

字符匹配

语法含义示例匹配
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)改变正则的整体行为,例如是否区分大小写、是否跨行匹配。

常用修饰符

修饰符PythonJavaScript含义
忽略大小写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 会指数级回溯
# 避免嵌套量词,必要时用原子分组/占用量词

匹配原则

  1. 默认贪婪,需要时加 ? 变惰性
  2. 匹配 HTML 等结构用惰性(.*?)更安全
  3. 避免嵌套量词(如 (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(无大写)
💡 提示

实战中先跑通小样例,再验证边界(空串、超长、特殊字符),最后应用到生产代码。

正则表达式 - 使用总结

总结正则的使用要点、常见陷阱和性能建议,帮你写出健壮高效的正则。

使用流程图

  1. 明确需求:是校验、提取、替换还是分割?
  2. 拆解模式:先写核心部分,再逐步完善
  3. 在线验证:regex101 等工具边写边测
  4. 测试边界:空串、超长文本、特殊字符
  5. 性能检查:避免嵌套量词、长回溯

常见陷阱

陷阱说明对策
忘记转义. * + ? 是元字符匹配字面量时加 \
锚点缺失校验时只匹配部分用 ^...$ 或 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}
URLhttps?://[\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

继续学习建议

  1. 把本页模式收藏为"个人速查表"
  2. 遇到新需求先在 regex101 上验证
  3. 逐步积累自己的模式库(团队复用)
  4. 关注高级主题:原子分组、回溯控制、Unicode 属性
💡 提示

正则模式会随业务变化,建议为常用模式编写单元测试,防止误伤正常数据。

第 1 / 16 节