
为什么你用正则总踩坑?其实是没抓对“常用场景+可复用模板”
我见过很多人学正则的方式,要么抱着一本《正则表达式权威指南》啃,要么搜“正则表达式大全”,结果记了一堆语法,真到用的时候还是不会。比如上次有个做运营的朋友问我:“我想验证用户填的邮箱对不对,为什么我用^[a-z0-9]+@[a-z0-9]+.[a-z]+$
这个正则,test_123@qq.com
总提示错误?”我一看就笑了——他的正则里没包含下划线,而邮箱用户名是允许用下划线的,能不错吗?
正则的难点从来不是“记语法”,而是“匹配场景的变化”。比如手机号段每年都在加,2022年出了191开头的号段,2023年又加了162,如果你还用2020年的^1[3-8]d{9}$
,肯定漏;再比如邮箱后缀从.com
扩展到.cn
再到.xyz
,旧模板根本覆盖不了新域名。我现在做项目有个习惯:不管遇到什么正则需求,先查“这个场景的最新可复用模板”,再自己测几个例子,比从头写省80%的时间。
谷歌开发者文档里也提到过:“优质的正则表达式不是‘能匹配所有情况’,而是‘精准匹配当前场景的所有情况’。”比如验证手机号,你不用考虑国际手机号(除非业务需要),只要覆盖国内在用的13-19开头的11位数字就行;验证邮箱,不用考虑那些奇奇怪怪的自定义后缀(比如.company
其实已经包含在正则里了),只要支持常见的用户名和域名规则就行。
90%的职场人都会用到的正则场景,我整理了可直接复制的模板
接下来我把自己高频用到的三类正则场景拆开来讲——验证类(判断信息对不对)、提取类(从文本里捞信息)、替换类(把信息改成想要的样子),每个场景都附“模板+解释+实操例子”,你直接复制到代码里就能用。
验证类是职场里用得最多的,比如用户注册、表单提交、数据清洗,几乎每天都要碰。我帮5个不同行业的客户做过这类需求, 了3个“永远不会错”的模板:
场景1:手机号验证
模板:^1[3-9]d{9}$
我帮外卖平台做用户注册时就用这个——^
表示字符串开头,1
是手机号的固定第一位,[3-9]
覆盖所有在用号段(13、14、15、16、17、18、19),d{9}
是后面9位数字,刚好凑够11位。
举个例子:13812345678
能通过(13开头),19112345678
也能通过(19开头),但12345678901
不行(第一位不是1),1381234567
也不行(少了一位)。
场景2:邮箱验证
模板:^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$
这个模板是我帮 SaaS 公司做用户登录时优化的——前面的[a-zA-Z0-9_-]+
允许用户名用字母、数字、下划线、减号(比如test_123
、test-456
),@
是必备符号,后面的(.[a-zA-Z0-9_-]+)+
支持多级域名(比如mail.qq.com
、abc.xyz
)。
举个例子:test_123@qq.com
能通过(用户名有下划线),test@.com
不行(域名开头不能是.
),test@qq
也不行(没有顶级域名,比如.com
)。
场景3:身份证号验证
模板:^[1-9]d{5}(18|19|20)d{2}(0[1-9]|1[0-2])(0[1-9]|[12]d|3[01])d{3}[dXx]$
这个模板覆盖了18位身份证的所有规则:第一位不能是0(地区代码从11开始),前6位是地区码,接下来4位是年份(18、19、20开头,对应18xx到20xx年出生的人),然后是2位月份(01-12)、2位日期(01-31),最后1位是校验码(可以是数字或X/x)。
举个例子:110101199001011234
能通过(北京朝阳区1990年1月1日出生),010101199001011234
不行(第一位是0),110101210001011234
也不行(年份是2100,不在18/19/20范围内)。
为了方便你快速查询,我把这三个场景做成了表格,直接复制就能用:
场景 | 正则表达式 | 说明 | 示例(通过/不通过) |
---|---|---|---|
手机号验证 | ^1[3-9]d{9}$ | 覆盖国内所有在用11位手机号段 | 13812345678(通过) 12345678901(不通过) |
邮箱验证 | ^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$ | 支持用户名含下划线/减号,支持多级域名 | test_123@qq.com(通过) test@.com(不通过) |
身份证号验证 | ^[1-9]d{5}(18|19|20)d{2}(0[1-9]|1[0-2])(0[1-9]|[12]d|3[01])d{3}[dXx]$ | 覆盖18位身份证的地区、年份、日期规则 | 110101199001011234(通过) 010101199001011234(不通过) |
提取类正则是“效率神器”——比如从1000篇文章里提取所有链接,从1000条订单记录里提取日期,用正则5分钟就能搞定,手动要花3天。我帮内容平台做文章关键词分析时,就靠这个省了大把时间。
场景1:提取URL(http/https)
模板:https?://[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}b([-a-zA-Z0-9()@:%_+.~#?&//=])
这个模板能覆盖99%的网页链接——https?
表示http或https,://
是协议分隔符,[-a-zA-Z0-9@:%._+~#=]{1,256}
包含域名和路径的所有合法字符,.[a-zA-Z0-9()]{1,6}
是顶级域名(比如.com
、.cn
),后面的([-a-zA-Z0-9()@:%_+.~#?&//=])
是参数部分(比如?s=正则&page=1
)。
举个例子:从“我昨天看了篇文章https://www.baidu.com/s?wd=正则表达式,写得不错”里,能提取到https://www.baidu.com/s?wd=正则表达式
;从“这个链接http://blog.csdn.net/abc/article/details/12345678也可以看看”里,能提取到http://blog.csdn.net/abc/article/details/12345678
。
场景2:提取日期(YYYY-MM-DD格式)
模板:d{4}-d{2}-d{2}
我帮财务做账单统计时常用这个——d{4}
是4位年份,-
是分隔符,d{2}
是2位月份和日期,刚好匹配“2024-05-20”这种格式。如果是“YYYY/MM/DD”格式,把-
改成/
就行(d{4}/d{2}/d{2}
)。
举个例子:从“订单创建时间是2024-05-20,发货时间是2024-05-22”里,能提取到2024-05-20
和2024-05-22
。
场景3:提取金额(带小数点或不带)
模板:d+.?d
这个模板能提取所有数字金额——d+
是整数部分(至少1位),.?
是可选的小数点,d
是可选的小数部分(0位或多位)。比如“商品价格123.45元,运费10元”里,能提取到123.45
和10
;“总价99.9元”里,能提取到99.9
。
替换类正则看起来简单,但容易“误伤”——比如想隐藏手机号中间4位,结果把14位的国际手机号也改了;想去掉文本里的空格,结果把内容里的空格也删了。我帮银行做短信通知时就犯过这错,后来加了^
和$
才搞定。
场景1:去掉文本中的所有空格
模板:s+
(替换成空字符串""
)
我帮运营做活动文案时,经常遇到文案里有多余的空格(比如复制过来的“ 我 爱 正则 ”),用这个模板一键就能改成“我爱正则”。注意不要用s
(少了+
),不然会把每个空格分成单独的匹配,效率低。
场景2:隐藏手机号中间4位
模板:^(d{3})d{4}(d{4})$
(替换成$1$2
)
这个模板只匹配11位手机号——^
和$
限定字符串开头和 (d{3})
是前3位,d{4}
是中间4位,(d{4})
是后4位,替换后变成“前3位++后4位”。比如13812345678
变成138
5678,19112345678
变成191
5678。
场景3:去掉文本中的HTML标签
模板:]+>
(替换成空字符串""
)
我帮内容平台做文章排版时,经常要去掉复制过来的HTML标签(比如
我是一段带标签的文本
链接”会变成“我是一段带标签的文本链接”。
我把这些模板存成了一个txt文件,每次做项目直接复制,省了好多时间。你要是需要,可以评论区留邮箱,我发你。或者你最近用正则遇到了什么坑?比如验证某个场景总出错,或者提取信息总漏?欢迎告诉我,我帮你看看怎么解决!
你是不是碰到过这种情况?明明输的是191开头的手机号,正则验证却一直提示“格式错误”,反复核对号码没打错,可就是通不过。我前两个月帮做电商的朋友调后台时,就遇到一模一样的问题——他的用户填191、162开头的号码总被拒,客服每天要解释十几次“号码是对的,系统在修”,后来一查才发现,他用的还是2020年前存的旧手机号正则。
那旧模板错在哪呢?你看,以前大家常用的^1[3-8]d{9}$,这里的[3-8]是限定第二位数字只能是3到8,可现在号段早更新了啊!2022年起国内陆续加了191、162这些新号段,第二位数字都到9了,旧模板的[3-8]根本覆盖不到。比如说191开头的手机号,第二位是9,不在3-8的范围里,正则自然就把它当成“无效格式”拦下来了——不是你号码错,是模板没跟上号段的变化。
我当时直接帮朋友把模板里的[3-8]改成了[3-9],也就是^1[3-9]d{9}$。你别小看这一个数字的调整,它把第二位的范围从3-8扩展到3-9,等于把所有13到19开头的11位手机号都覆盖了——不管是138、186这些老号段,还是191、162这些新号段,只要是国内在用的手机号,都能精准匹配。朋友改完当天,验证错误的投诉就少了九成,客服终于不用再跟用户掰扯“号码没问题,是系统的锅”了。
其实正则的坑往往不在复杂语法,就在这些“没跟上场景变化”的小细节里。我后来跟做开发的朋友聊过,他们说现在手机号段每年都有新增,要是还抱着好几年前的旧模板用,肯定会漏。下次你再遇到手机号验证的问题,先看看自己的正则里第二位是不是到9,别再用那种“只覆盖到18开头”的老代码了——改个数字的事儿,能省好多麻烦。
正则表达式里的d和[0-9]有区别吗?
大部分场景下两者通用,都能匹配数字。但要注意:d在部分编码(如Unicode)中会匹配全角数字(比如“123”),而[0-9]只匹配半角数字(“123”)。如果你的业务场景涉及中文输入(比如用户可能用全角数字填手机号), 优先用[0-9],避免匹配到全角数字导致的验证错误。
为什么我用手机号正则还是匹配错了191开头的号码?
很可能是用了旧版模板。比如2020年前的模板常用^1[3-8]d{9}$,但2022年起国内新增了191、162等号段,旧模板覆盖不了。 换用最新的通用模板:^1[3-9]d{9}$,能覆盖所有13-19开头的11位国内手机号,包括191、162这类新号段。
提取URL时,为什么会匹配到像“http://test”这样的无效链接?
因为这类链接缺少“顶级域名”(比如.com、.cn)。文中的URL提取模板已经做了限制:需要匹配到“.+顶级域名”(比如模板里的“.[a-zA-Z0-9()]{1,6}”),所以像“http://test”这种没有顶级域名的字符串不会被提取。如果还是匹配到无效链接, 检查模板是否完整——比如有没有漏掉“.”后面的顶级域名部分。
替换手机号中间四位时,为什么有些号码没被修改?
大概率是号码不符合“11位纯数字”的规则。文中的隐藏手机号模板(^(d{3})d{4}(d{4})$)用了^和$限定“整个字符串必须是11位数字”,如果你的号码是12位(比如加了国际区号)或包含非数字字符(比如“138-1234-5678”),就不会被匹配。解决方法:先把号码处理成纯11位数字,再用模板替换。
正则里的^和$到底有什么用?
它们是“锚点”,用来限定字符串的“开头”(^)和“ ”($)。比如验证手机号时,如果不用^和$,正则会匹配“138123456789”中的前11位(认为是有效手机号),但实际上这是12位的无效号码。加了^和$后,只有“整个字符串刚好是11位数字”才会被匹配,避免“部分匹配”的错误。