天天看点

文盲的正则表达式入门,实战篇(欢迎提问,持续更新)如何写出正则?

目录

如何写出正则?

手机号码正则

电子信箱地址正则 

符合一定规律的字符串匹配

密码复杂度验证正则

提取html标签外(正文中)的内容

之前写的文章文盲的正则表达式入门,个人认为写的还可以,但是网络上充斥着的同质化内容太多了,结果整整几年了,也没几个人看过,郁闷哦

再有就是,虽然老顾推荐给了几个人看,但感觉小朋友们的正则水平提升的并不明显,也许读正则都费劲?

那么,这次老顾就结合自己的正则入门来几个实战,来帮助新手入门正则吧。

如何写出正则?

正则的规则,各定义的意义已经在正则入门篇里讲过了,这边不再重复,那么如何写出正则呢?其实这就是把我们的思路改成正则的逻辑,就像汉语翻译成英语,日语翻译成汉语一样。你的思路越清晰,那么正则的规则就越详细。

手机号码正则

一个常见的例子:手机号验证。

大咧咧的人,比如老顾,他的思路是这样的:数字1开头(开头的意义表示前边不能有其它数字哦),后边跟10个数字,且10个数字后没有跟随其它数字,那么这个正则写下来就是

^1    ,数字1开头
\d{10},10个任意数字
$

组合起来就是 ^1\d{10}$
           

这个用来验证单一的手机没问题,但如果在文中提取,那么就需要变形一下

(?<!\d)    前边不能是数字
1          数字1开头
\d{10}     10个任意数字
(?!\d)     后边不能是数字

组合起来

(?<!\d)1\d{10}(?!\d)
           

这样,这个正则就可以用来提取文本中的手机号码了

注:这里用到的左断言,js是不支持左断言的,需要自己注意哦

同样是手机号码,有的人就很细心,非得把号段也给囊括进来,不是指定的号段,就不是国内大陆的手机号码。。。Hmmmm,行吧,反正这样的人确实有不少

那么,这样的人,他会去百度一下,国内手机号段都有哪些

文盲的正则表达式入门,实战篇(欢迎提问,持续更新)如何写出正则?

然后,他们搞到了这么一个表格,于是,他们就按照这个内容写正则了,思路很清奇的哦

数字1开头,这个不变,然后,第二位的数字只有3456789,为了更严格,他们不会写成[3456789],因为每个数字后可以跟随的第三位数字范围不一样,于是,他们把正则写成了这样

^1([38]\d|4[01456789]|5[012356789]|6[567]|7[35678]|9[189])\d{8}$

拆开就是

^1
(
    [38]\d
    |
    4[01456789]
    |
    5[012356789]
    |
    6[567]
    |
    7[35678]
    |
    9[189]
)
\d{8}
$

13和18的第三位数字不限,0-9都有,所以是 [38]\d
14里面第三位没有2和3
15里面第三位没有4
其他类似。。。
           

额。。。。如果有看不明白的,记得留言哦。

看看,手机号码的验证或匹配,是不是很简单,基本上思路摆出来,翻译成正则符号即可,不明白各个符号的,可以回头重新看正则入门哦

电子信箱地址正则 

那么,再来一个常见的,比如电子信箱。

好的,电子信箱的格式,咱们来描述一下:

1、有且只有一个@符号

2、只能由字母数字下划线点和减号构成其他部分

3、@符号之后,为域名部分,域名部分没有下划线支持,@符号前为用户名部分,可以支持描述2的所有字符

4、域名长度不确定,可能由多个.,至少有1个.,域名结束部分为2-4个字符(中文域名就算了,不想支持)

那么,这个正则按照上边的逻辑来实现一下

[a-zA-Z0-9_\.-]+@([a-zA-Z0-9-]+\.)+[a-z0-9]{2,4}

首先,有且只有一个@

然后,用户名部分由字母数字下划线点和减号构成,即:[a-zA-Z0-9_\.-]

在然后是域名部分,由字母数字点和减号构成,但是.要作为域名分隔符,所以他的字符集为字母数字及减号,即:[a-zA-Z0-9-]

域名构成格式为 字符.字符.字符,所以除去最后一个字符,前边的片段就可以写成 ([a-zA-Z0-9-]+\.)+

最后,得出信箱正则 [a-zA-Z0-9_\.-]+@([a-zA-Z0-9-]+\.)+[a-z0-9]{2,4}
           

符合一定规律的字符串匹配

然后,老顾碰到一个同学问了个正则匹配问题,有一个字符串:“名称:量子力学教程,作者:周世勋,ISBN:9787040262780,出版社:高教名称:量子力学教程(第二版)学习指导,作者:倪致祥,ISBN:9787040303506,出版社:高教”,怎么把他分成多本书的信息,且要保留分组

首先,这个字符串并不规整,他这个字符串包含了两本书的信息,但第一本数的出版社信息和第二本数的名称描述连在一起了。。。但整体上看,这个字符串还是比较规整的

那么,我们来描述一下:

1、以“名称:”开头的字符串,包含作者、ISBN、出版社信息,且描述都用:,描述后的内容都不包括逗号,以逗号结束描述的对应信息

那么,第一个正则片段应该是

(名称):([^,]*?),(作者):([^,]*?),(ISBN):([^,]*?),(出版社):([^,]*?)
           

应该没有人看不懂这个吧

但是这个正则匹配出来的结果,略微不那么对头,出版社信息不见了?

文盲的正则表达式入门,实战篇(欢迎提问,持续更新)如何写出正则?

 如果最后一个括号内,不加非贪婪模式,那么他又没办法将字符串分成两条匹配了

所以,这个正则加个右断言修饰好了

出版社后的内容后边要么字符串结束,要么是下一本书的开头,即“名称:”

所以正则修改一下

(名称):([^,]*?),(作者):([^,]*?),(ISBN):([^,]*?),(出版社):([^,]*?)(?=(?:$|名称:))
           

(?=(?:$|名称:)) 是整个片段(?=) 是右断言,(?:)是不进行捕获的分组 去掉 ?: ($|名称:) 就是字符串结尾,或名称:字符匹配(摘自留言回复)

使用js来测试一下

var re = '(名称):([^,]*?),(作者):([^,]*?),(ISBN):([^,]*?),(出版社):([^,]*?)(?=(?:$|名称:))';
var str = '名称:量子力学教程,作者:周世勋,ISBN:9787040262780,出版社:高教名称:量子力学教程(第二版)学习指导,作者:倪致祥,ISBN:9787040303506,出版社:高教';
var m = str.match(new RegExp(re,'gi'));
for(var i=0;i<m.length;i++){
    console.log(new RegExp(re,'gi').exec(m[i]));
}
           
文盲的正则表达式入门,实战篇(欢迎提问,持续更新)如何写出正则?

 很简单的就能完成匹配提取需求了

密码复杂度验证正则

然后,又一个很常用的正则验证需求,带有复杂度要求的密码验证 ^v^

一般来说,密码要求的字符是:字母数字以及其他各种字符(ascII32-127),多少多少位长度

但现在由于各种密码泄露很多早期密码都被人做成词典了,所以,很久之前,对密码就有了复杂度要求,比如

由字母大写,字母小写,数字,符号组成,至少包含三种类型,长度8-16,我们就按照这个来实现正则吧

首先,确定字符串长度

^[\u0020-\u007f]{8,16}$

然后,我们使用断言的方式来判断密码字符串中包含了几种逻辑

^(?=.*?[0-9])[\u0020-\u007f]{8,16}$

(?=.*?[0-9]) 表示后续字符串中有数字

(?=.*?[a-z]) 表示后续字符串中有小写字母

(?=.*?[A-Z]) 表示后续字符串中有大写字母

(?=.*?[^a-zA-Z0-9]) 表示后续字符串中有字母数字以外的符号

现在需要密码中至少包含三种逻辑。。。Hmmmmm

完全符合四个要求的正则很容易实现

^(?=.*?[0-9])(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[^a-zA-Z0-9])[\u0020-\u007f]{8,16}$

直接用四次断言判断即可,但如果只实现其中一种呢。。。。Hmmmm

^((?=.*?[0-9])|(?=.*?[a-z])|(?=.*?[A-Z])|(?=.*?[^a-zA-Z0-9]))[\u0020-\u007f]{8,16}$

符合一个条件的也好弄,直接在断言里面加或的关系。。。

那么,通过断言的不同组合,就可以得到符合三种条件的正则了

^((?=.*?[0-9])(?=.*?[a-z])(?=.*?[A-Z])|(?=.*?[0-9])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[0-9])(?=.*?[A-Z])(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[^a-zA-Z0-9]))[\u0020-\u007f]{8,16}$

这个正则到是能判断至少符合三个规则的密码复杂度。。。。但也太累赘了,如果复杂度要求变了,有更多的条件,比如字母中至少含有asdfg中的一个,字母中至少包含yuiop中的一个。。。。总的条件数编程了六个,至少包含三个的话。。。正则没法看了,所以,对于验证来说,有些可以用正则,有些则不要用正则了,用个程序随便判断下,都比纯正则简单了



           

提取html标签外(正文中)的内容

(2021-07-27 更新)

我们有任意html,通常是通过采集获得的,那么有这么个字符串,我们要匹配其中的内容,有时候会匹配的比我们预期的内容要多,比如匹配一个包含 style 单词的片段

style="[^"]*"
           

结果就会发现,匹配出来了N多N多的信息,但绝大部分是我们不关注的,因为他们来自标签的属性,而我们需要的是正文中相关的内容,用右断言会非常简单的解决这个问题

style="[^"]*"(?=[^>]*?<)
           

前边内容不变,右边我们只需要判断,在下一个左尖括号前,没有出现右尖括号。嗯嗯,多简单,逻辑一下子就清晰了。至于为什么是这个逻辑,就不细讲了,大家都知道,一对尖括号就是一个标签嘛。

-------------------------------------------------------

那么,本文将持续更新,有正则问题的,可以在发个留言哦,如果问题很有代表性,就更新到正文内哦

继续阅读