无痛的正则表达式,今天学完,明天找工作(上)

大家是否和我一样,学正则表达式不得要领,常学常忘,常忘常学,沉(tong)迷(ku)到无法自拔。

后来,我做了很多实际项目,才发现了正则的学习门道。本号将多年武功内力浓缩成两篇秘籍,可以无痛、快捷地掌握正则要义。上篇,我总结了7个要点,几乎可以解决90%的正则问题。下篇我会讲解正则表达式剩余知识点,并进行完整总结。


目录

一、问题引入

1.实际问题

2.推荐3个网站

3.使用正则一键提取 

二、正则要点

1.固定字符,直接写

2.可能字符,方括号[]

3.重复次数,花括号{}

4.或者选择,1竖线|

5.提取字符,圆括号()

6.反向引用,反斜杠\

7.零宽断言,问等叹  ?<=   ?<!   ?=    ?!

三、动手练习


一、问题引入

1.实际问题

的有某网友在下班前半小时接到老板要求,提取1万多个商铺的手机(电子表格见下图),商铺座机、商铺400客服电话都不要。假若是你接到任务,可以在多长时间内完成老板任务,能按时下班吗?

2.推荐3个网站

测试正则网站  正则表达式在线测试 - 站长工具(速度快,功能够用)或者regex101: build, test, and debug regex(速度慢,功能全),二选一即可。

的正则图解网站  Regexper

3.使用正则一键提取 

复制电话到站长工具,使用正则表达式  1[0-9]{10}  即可提取所有电话

正则表达式功能强大,接下来将以电话提取为题目,通过7个要点学习如何通过正则提取电话。

二、正则要点

1.固定字符,直接写

“固定字符”就是在写正则表达式时是固定的,确定的字符。上图中正则表达式1[0-9]{10},其中1是所有手机都是1打头,是固定的。

如果老板要找上海的6打头的座机,可以写021-6[0-9]{7},其中021-6就是固定的字符,可以直接写。

如果老板要找上海的6打头且末位是7的座机,冰雪聪明的读者,你现在能写吗?

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个要点,几乎可以解决正则90%的问题。光说不练假把式,小试牛刀一下吧:

题目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。

题目4:提取红楼梦中五言和七言诗。正则[\u4e00-\u9fa5]表示一个汉字

附录(练习用电话号码,都已被我修改过,不是真实电话。):

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

关注“***” ,欢迎留言提问吐槽!

  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值