家是否和我一样,学正则表达式不得要领,常学常忘,常忘常学,沉(tong)迷(ku)到无法自拔。
后来,我做了很多实际项目,才发现了正则的学习门道。本号将多年武功内力浓缩成两篇秘籍,可以无痛、快捷地掌握正则要义。上篇,我总结了7个要点,几乎可以解决99%的正则问题。下篇我会讲解正则表达式剩余知识点,并进行完整总结。
目录
一、问题引入
1.实际问题
2.推荐3个网站
3.复制电话到站长工具,使用正则表达式 1[0-9]{10} 即可提取所有电话
二、正则要点
1:普通字符,直接写
2:一批字符,方括号[]
3:重复次数,花括号{}
4:或者选择,1竖线|
5:一组字符,圆括号()
6:反向引用,斜杠数\
7:零宽断言,等不等?= ?! ?<= ?
三、动手练习
一、问题引入
1.实际问题
有某网友在下班前半小时接到老板要求,提取1万多个商铺的手机(电子表格见下图),商铺座机、商铺400客服电话都不要。假若是你接到任务,可以在多长时间内完成老板任务,能按时下班吗?
2.推荐3个网站
测试正则网站 http://tool.chinaz.com/regex(速度快,功能够用)或者https://regex101.com/(速度慢,功能全),二选一即可。
正则图解网站 https://regexper.com/
3.使用正则一键提取
复制电话到站长工具,使用正则表达式 1[0-9]{10} 即可提取所有电话
正则表达式功能强大,接下来将以电话提取为题目,通过7个要点学习如何通过正则提取电话。
二、正则要点
1.普通字符,直接写
上图中正则表达式1[0-9]{10},其中1是普通字符,表示所有手机都是1打头。
如果老板要找上海的6打头的座机,可以写021-6[0-9]{7},其中021-6就是普通字符,直接写。
如果老板要找上海的6打头且末位是8的座机,冰雪聪明的读者,你现在能写吗?
2.一批字符,方括号[]
手机号码是1打头,后面的数字是0到9之中任意一个数。正则表达式规定方括号可以写出所有情况,如:[0123456789]或者[1357902468]等等,表明方括号处的符号是0到9之中某一个。
如果是小写字母,可以这样[abcdefghijklmnopqrstuvwxyz]或者[qwertyuiopasdfghjklzxcvbnm]。
但是这样写太复杂,可以简化写法[0-9],[a-z]。注意,不可以[9-0]或者[z-a]。why?不要问我,问美国标准化信息协会,他们规定数字最小的是0最大的是9,小写字母最小的是a最大的是z,具体见ASCII代码表。
3.重复次数,花括号{}
手机号码共11位,1打头,后面10位都是数字,方括号[0-9]可以表明任意一个数字。接下来,就可以笨笨地写出正则表达式:1[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]。
正则如此聪明,上述笨写法当然可以简化,用花括号就可以表明重复多少次,手机号码可以简写成:1[0-9]{10}。{10}表明前面的数字[0-9]必须重复10次。
假设,只是假设,我们手机号是9-11位的,那么正则可以简写成:1[0-9]{8,10}。假设我们手机号码最少9位,最多多少位不确定,那么正则可以简写成:1[0-9]{8,}。
4.或者选择,1竖线|
假设老板要大家找出武汉和上海的座机电话,大家该怎么办?可以分两次用正则找,然后复制出来粘贴到一起交差。如:先找上海座机021-[0-9]{8},然后找武汉座机027-[0-9]{8}。
聪明的大家可能想到方括号,可以一次性查找两地电话。这里我不炒现饭,不用方括号的解法,介绍一个新的正则功能“或者”。
通过或者|,可以简化成1次进行查找,或者符号是1条竖线|,正则表达式:021-[0-9]{8}|027-[0-9]{8}。
5.一组字符,圆括号()
数学中通过括号可以提取公因式,如:ma+mb+mc=m(a+b+c)。
上例中一次提取上海和武汉座机,就可以通过圆括号进行进一步简化,-[0-9]{8}可以提取出来,如:(027|021)-[0-9]{8},或者02(7|1)-[0-9]{8}。
圆括号是分组的意思,通过分组,让或者的范围从整个表达式缩小到分组这样的一个小局部。下图在regexper.com中分3次绘制。
6.反向引用,斜杠数\
回文是有趣的文字现象,如:上海自来水来自海上。座机电话号码也可以有回文形式,如:021-87655678。由于回文给出的规律是第1个数和第8个数相同,第2个数和第7个数相同,第3个数和第6个数相同,第4个数和第5个数相同,这样正则就必须表达第几个数。正则用分组和反向引用来解决这个问题。
首先,电话号码的前4个数字进行分组,正则表达式:([0-9])([0-9])([0-9])([0-9])。
然后,这4个分组叫1号分组,2号分组,3号分组,4号分组,分别用反斜杠数字表达,如:\1,\2,\3,\4。
最后,回文的正则表达为:([0-9])([0-9])([0-9])([0-9])\4\3\2\1。
7.零宽断言,等不等?= ?! ?<= ?<!
在回文电话中,意外抓取到了手机号码中的回文,如果老板要求回文座机号码,正则可以解决吗?
我们的例子中,座机号码和手机号码的区别是 座机号码有一个横线,那么回文座机号码就有了一个要求,回文必须前面有一个横线,而横线不要进行正则匹配。那么零宽断言就可以解决,正则表达式:(?<=-)([0-9])([0-9])([0-9])([0-9])\4\3\2\1,可以匹配座机电话中的回文。
(?<=-)叫零宽度正回顾后发断言,表明横线-必须出现,但是匹配结果中不出现横线-。
如果不要前面出现横线,可以使用零宽度负回顾后发断言(?<!-),会匹配非座机中的回文,正则表达式:(?<!-)([0-9])([0-9])([0-9])([0-9])\4\3\2\1。
可以使用零宽度正回顾先发断言(?=-),会匹配回文后面有横线的回文,正则表达式:([0-9])([0-9])([0-9])([0-9])\4\3\2\1(?=-)。
可以使用零宽度负回顾先发断言(?!-),会匹配回文后面有横线的回文,正则表达式:([0-9])([0-9])([0-9])([0-9])\4\3\2\1(?!-)。
三、动手练习
到此,已经学完正则7个要点,几乎可以解决正则99%的问题。光说不练假把式,小试牛刀一下吧:
题目1: 前后都是空格的6位数字的邮编,不匹配空格只匹配6位数字。
题目2:小时分钟秒,形如HH:MM:SS。小时HH是00-23,必须2位数。分钟MM是00-59,必须2位数。秒SS是00-59,必须2位数。
题目3:年月日,形如YYYY-MM-DD或者YYYY/MM/DD。年YYYY是1000到2999。月是1到12或01到12,可以1位数,也可以2位数。日是1到31或01到31,可以1位数,也可以2位数,不要求分析大月小月。注意前后分隔符必须统一,不允许YYYY-MM/DD或者YYYY/MM-DD。
附录(练习用电话号码,都已被我修改过,不是真实电话。):
18121259651
021-54251306
027-64337018
020-54272788
021-33687788/18621164392
13124885895
021-54566545
18285522558
15807697545
021-54277790
13166257711
021-52835890
021-62099872
021-68321717
17802169959
4008988777
021-62780757
027-62341717
021-60318297
020-62155310
027-62771517
020-62459535
027-62270156
13918766200
021-52801923
021-62810973
18075106991/021-62645263
021-61169555
021-52806899
021-62091717
021-62152777
021-62365907
关注“关山号 ” (guanshan-hao),欢迎留言提问吐槽!
————————————————
版权声明:本文为CSDN博主「testcqw」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cqwygg/article/details/106893222