正则表达式实战:从"看天书"到"顺手就写"

举报
yd_237615889 发表于 2026/09/09 22:48:31 2026/09/09
【摘要】 正则表达式实战:从"看天书"到"顺手就写"很多人学正则的方式是打开一张几十行的元字符总表开始背,背到"零宽断言"就放弃,之后见到正则还是像看天书。其实正则不是背出来的:记住 9 类字符 + 理解 4 个概念,就能覆盖日常 90% 的场景。剩下的部分,交给调试工具和这篇的配方库。这篇不讲学院派理论,按"能上手写、能看懂别人的、能避开事故"三个目标来组织。一、核心字符:一张表覆盖 90%类别写法...

正则表达式实战:从"看天书""顺手就写"

很多人学正则的方式是打开一张几十行的元字符总表开始背,背到"零宽断言"就放弃,之后见到正则还是像看天书。其实正则不是背出来的:记住 9 类字符 + 理解 4 个概念,就能覆盖日常 90% 的场景。剩下的部分,交给调试工具和这篇的配方库。

这篇不讲学院派理论,按"能上手写、能看懂别人的、能避开事故"三个目标来组织。

一、核心字符:一张表覆盖 90%

类别

写法

含义

字符组

[abc][a-z][^x]

任选其一 / 范围任选 / 排除

预定义类

\d \w \s

数字 / 单词字符 / 空白(大写为补集)

量词

* + ? {n,m}

0 次起 / 1 次起 / 0 1 / 次数区间

懒惰量词

*? +? ??

在贪婪基础上加问号,尽量少匹配

锚点

^ $ \b

行首 / 行尾 / 词边界

分组

(…)(?:…)(?P<>…)

捕获 / 不捕获 / 命名(语法因语言而异)

a|b

左右任选

先后看

(?=x) (?!x) (?<=x) (?<!x)

后面是/不是 x,前面是/不是 x

转义

\. \* \\

元字符还原为字面含义

 

正则的最小可用配置就是这一张表。下面四个概念决定你是"查表拼凑"还是"流畅书写"

二、四个概念:从查表到书写

概念 1:贪婪与懒惰

量词默认贪婪:尽可能多吃。<div>.*</div> 遇到一行里有多个 div,会从第一个 <div> 一路吃到最后一个 </div>。在量词后面加 ? 变懒惰,尽可能少吃:

文本:<div>a</div><div>b</div>

 

贪婪:<div>.*</div>    匹配整个字符串(吃到最后)

懒惰:<div>.*?</div>   分两次,各匹配一个 div

更推荐的做法是用排除法代替懒惰:<div>[^<]*</div>——语义更明确,性能也更好。

概念 2:分组与引用

圆括号除了分组还捕获:提取日志里的时间戳、把匹配的片段拿来替换,全靠它。两件小事记牢:

·         只想分组不想捕获,用 (?:…)——不占捕获编号,不浪费内存

·         命名组让长正则可读:Python (?P<time>…).NET/JS (?<time>…),方言不同但思想一致

概念 3:先后看(零宽断言)

(?=x) (?<=x) 匹配的是"位置"而不是字符——像站在原地往右/往左看一眼,条件满足才算命中,本身不吃任何字符。最经典的应用是千分位:

import re

re.sub(r'(?<=\d)(?=(\d{3})+$)', ',', '12345678')   # → '12,345,678'

规则:每个"后面还剩 3 的倍数个数字"的位置前面插逗号。注意这个配方只适用于纯整数串,含小数时会切到小数部分。

概念 4:标志位

·         i:忽略大小写

·         g:全局匹配(不加只匹配第一个;findall API 天然全局)

·         m:多行模式——不加时 ^ $ 只认整个字符串的首尾,加了才逐行生效

·         s:让 . 也能匹配换行符

三、高频配方:拿走就用

1. 手机号(中国大陆)

1[3-9]\d{9}

提取场景够用;做校验时加上锚点 ^1[3-9]\d{9}$,否则字符串里夹一段 11 位数字也会放行。

2. 邮箱(务实版)

^[^\s@]+@[^\s@]+\.[^\s@]+$

完整 RFC 规范的正则可以写到几百字符,不值得。这条只验证"没有空格、有一个 @@ 后有点"——真正的校验靠发送确认邮件,这是行业共识。

3. 日期 YYYY-MM-DD(半严格)

\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])

月份和日期范围已校验,但 2026-02-31 仍能通过——日历合法性交给日期库,正则只挡格式错误,这是分工的正确姿势。

4. IPv4(严格版)

((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)

每段 0–255 的经典写法。用在日志提取里时两侧加 \b 或显式锚点,防止 999.1.1.1 被部分匹配。

5. 从日志行提取字段(命名组实战)

2026-09-09 22:04:31 [ERROR] 10.2.3.4 payment timeout after 3000ms

^(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?P<level>\w+)\] (?P<ip>\d{1,3}(\.\d{1,3}){3}) (?P<msg>.+)$

一条正则把整行拆成 time / level / ip / msg 四个字段——日志解析器的基本功就是它。

6. 密码强度(多条件与先看)

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$

三个 (?=…) 各自独立检查"整串里存在小写/大写/数字",最后 .{8,} 管长度。多个先后看叠加做""逻辑,是这个技巧的核心用法。

四、回溯灾难:正则界的事故高发区

引擎匹配失败时会回溯重试。大多数时候无所谓,但嵌套量词会让回溯次数指数级爆炸:

^(\d+)*$      # 危险:量词套量词

^(a+)+$       # 危险:同上

拿一串 30 个字符去匹配失败,引擎要回溯数十亿次——服务直接卡死,这类攻击叫 ReDoS。而且它常出现在用户输入校验里(攻击者专门构造这种字符串),属于安全漏洞。

修复方法固定两条:消灭嵌套量词^(\d+)*$ 改成 ^\d+$),用排除法替代点号"[^"]*" 优于 ".*?")。上线前把正则放到长反例串上压一遍,或者干脆用 RE2 这类保证线性时间的引擎。

五、五个常见坑

·         忘了转义点号file.pdf 里的 . 匹配任意字符,fileXpdf 也会命中。字面点号写 \.,同理 + ( ) [ ] { } | * ? $ ^ \ 都要转义

·         贪婪吃太多:见概念 1,多个同类标签挤在一行时 .* 会跨越边界。用 [^x]* 排除法或 *? 懒惰

·         `\b` 在中文里不靠谱:词边界依赖 \w 的定义,中文在不同引擎、不同模式下进不进 \w 都不一样。处理中文用明确的字符组([\u4e00-\u9fa5])和锚点,别赌 \b

·         多行文本忘了 `m` 标志^ $ 默认只匹配整串首尾,逐行匹配必须开多行模式,否则整个文件只有第一行能被"行首"命中

·         跨语言照抄正则JS 旧版不支持 lookbehind.NET \d 默认匹配全角数字;命名组语法各有写法。跨语言迁移前先查方言,用语言自带的原生测试跑一遍

六、工具与工作流:三个动作代替死记

1.       regex101 调试:贴样本写正则右侧实时高亮和逐 token 解释,看不懂别人正则时把粘进去读解释,比任何教程都快

2.       真实样本驱动:从生产数据里抓正反例各 20 条,正例必命中、反例必不中,先有样本再写正则

3.       固化成单测:正则是"看起来对"最容易骗人的代码,正反例写成单元测试才敢改

速查卡

场景

正则

手机号校验

^1[3-9]\d{9}$

邮箱(务实版)

^[^\s@]+@[^\s@]+\.[^\s@]+$

日期格式

\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])

千分位

(?<=\d)(?=(\d{3})+$) 替换为逗号

日志行提取

命名组,见配方 5

密码强度

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$

防回溯灾难

禁嵌套量词,点号换排除法

 

写在最后

正则的上限不是"记住多少语法",而是"能否用真实样本验证它"9 类字符是词汇量,4 个概念是语法,配方库是肌肉记忆,样本和单测是安全网——四样配齐,正则就从天书变成了顺手的日常工具。

从打开 regex101、贴上一条你今天的真实日志开始吧。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。