php邮箱正则下划线,正则表达式-邮箱正则解析引导

1,强推一个github上学习正则的项目

2,常见的邮箱格式

1,数字 + @ + 数字 + .com:[email protected]

2,数字、字母 + 下划线 + @ + 数字|字母 + .com:zhangsan_123@163(qq).com

3,数字、字母、下划线 + @ + 数字、字母、中划线- + .com:[email protected]

补充说明:为了下文便于理解,假定上述邮箱字符串作以下拆分:

1)第一部分:@符号之前的内容

2)第二部分:@符号之后,.符号之前的部分

3)第三部分:.符号之后的部分(虽然上述链接格式是以顶级域名com为结尾,但并不排除出现类似.com.cn这样的结构)

3,正则解析

3.0,前言

1,基于每个人的思维模式,理解能力等因素,为了使您的正则学习不误入歧途,请确保在参考了一定资料(如菜鸟教程、或是上述推荐的github项目)之后,有了初步的基础后,再参考本文,作进一步的参考印证会更好一点,请认真考虑我的提议!

2,本文适合正则初学者阅读;本意还是为了引导初学者在学习过程中如何去思考构造及优化正则表达式;本文所用的例子并不一定全部涵盖现实中所有的邮箱格式。

故在阅读过程中,希望您可以尝试考虑本文没有提及的地方,以及该如何优化?同时,也欢迎您在下方留言处予以指正,非常感谢!

3,本文篇幅略长,您最好是有时间了跟着操作一遍比较好。

4,部分元字符因为偷懒的缘故,并未一一列出,请综合参考各方资料。

3.1,思考题:如何(仅)匹配数字或字母其中一种情况?

1,会的同学请略过

2,相关元字符:

\d   -  表示[0-9]的整数数字;

\w  -  表示字母、数字、下划线

+   -  表示该符号(即符号+)前出现的子表达式需要至少出现1次;

*   -   表示该符号前出现的子表达式需要至少出现0次

? -   表示该字符前出现的子表达式可以出现0次或1次

^   -   匹配输入字符的开始位置

$   -   匹配输入字符的结束位置

?:  -   匹配 pattern 但不获取匹配结果

x|y: -  匹配x或匹配y

针对上述思考题,我将尝试分步进行校验:

1)如何仅匹配数字?

匹配单个整数的元字符是\d,匹配多个整数数字字符串可以用\d+(当然,*其实也是可以的,显然元字符+的匹配结果是元字符*的匹配结果的子集);那如何保证整个字符串只能出现数字呢?答案是用元字符^和$去限制输入值;

也即是说,^与\d结合告诉程序需要排除输入字符的开始位置不为数字的情况($符号同理)。

同时满足这两个限制才会输出匹配结果(至于中间不为数字的情况嘛,该表达式走不下去,因为当判断到非数字的情况的时候,意味着\d+匹配结束,然后$符号发现结束位置不为数字,匹配失败;您可以试着解除$元字符的限制,看看中间不为数字的匹配结果)。

2)如何仅匹配字母?

构造过程同上。需要注意的是,在当前限制下,\w不再适合用来匹配字母,因为\w同时还能匹配数字和下划线。

所以我尝试将之替换为[a-zA-Z]。

3)如何(仅)匹配数字或字母其中一种情况?

将前两步的结果,构造成x|y形式。

4)针对第3步的结果,该如何优化?

需要提醒的是,由于第3步中,我将第1步和第2步中的结果组成了“x|y”这种形式,为了不使这两个子表达式造成歧义,我用了两个小括号将其包裹起来;

于是我面临了一个问题:由于小括号除了通俗意义上的隔离、提高优先级等作用外;它在正则里还有一个作用是收集并存储括号内子表达式的匹配结果。因此,当我并不需要这个子表达式的匹配结果时,我可以用元字符“?:”来实现这个想法。当然,如果您需要用到的话,则并不需要考虑?:元字符的作用。

3.2,数字 + @ + 数字 + .com类:

相关元字符:

\d   -  表示[0-9]的整数数字;

\w  -  表示字母、数字、下划线

+   -  表示该符号(即符号+)前出现的子表达式需要至少出现1次;

*   -   表示该符号前出现的子表达式需要至少出现0次

? -   表示该字符前出现的子表达式可以出现0次或1次

^   -   略

.   -    略

?:  -   匹配 pattern 但不获取匹配结果

虽然常规下,使用+ 和 * 是为了让符号前的最后一个字符出现多次,例如,zo+里,+号所应用的字符就是o,而不是zo,所以zo+这个正则,回去匹配zo,zoo,zo...,却不会去匹配zozo;

但上述表述中,之所以描述为菜鸟教程里表述的“子表达式”,是因为“字符”的概念并不同于常规意义下的char,我是可以通过小括号()去构造新的“字符”的(而常规意义下,超出一个char的字符,再表述为字符就有点歧义了,所以在初学阶段,理解为子表达式会更合适一点);这意味着,我要向匹配zozo的话,可以用正则表达式(zo)+

虽然上述想尽可能去解释清楚这个概念,但为了防止误解,或是为了加深印象,您最好可以多做尝试。

所以上述正则可以对号入座:/\d+@\d+.\w+/

在优化上述正则前,我想就@和.这样的字符引申出一个概念:在无解的情况下,可以使用通俗语言表达形式去构造正则;

原因是如下:

1),某些符号在不具备很强复用性的情况下是没有简写形式的,这也是为什么对于[a-zA-Z0-9_]这个正则可以用 \w来替代;(当然,基于下划线都被丢到\w来看,哪天@符号被丢进去倒也不奇怪,毕竟字母和数字也没很强的关联不是?)

2),在精通之前,您最好做好先初步构造,再尝试优化这一流程的心理准备;比如上述正则还可以更粗糙一点: /\d+@\d+.com/(虽然这样一来,就屏蔽了.org,.cn这类的顶级域名)

那么对上述正则,可以如何优化呢?

1)@符号前有个\d+,@符号后有个\d+,那能不能将他们合在一起呢?

这种思路是可以的,主要在于@符号如何处理呢?可以考虑用元字符“?"来标识它可出现可不出现。然后为了保证合并后的子表达式出现两次,我需要将其用小括号包裹,并用+号来对他进行扩展(其实*号也可以,毕竟考虑到子表达式需要出现2次,那么>=0和>=1在这种情况下就没什么区别了);于是我得到了新的正则 /(\d+@?)+.\w+/

2)虽然我在优化1)处用小括号对@符号的前后进行了整合,但小括号有个特性—对括号内的子表达式进行收集和存储,于是,我得到了下边的结果:

/(\d+@?)+.\w+/的匹配结果

对于上述结果,您可以用(?:pattern)表达式来进行设定,它的含义是,匹配pattern部分的内容,但是,不缓存其匹配结果。基于对该元字符的应用,我得到了如下结果:

/(?:\d+@?)+.\w+/的匹配结果

3)对于上述正则表达式,您也许会发现,其对邮箱的起始字符未限定

ps:我当前是在基于对“数字 + @ + 数字 + .com”这一类邮箱做处理,所以按照这类邮箱的定义,是不应该出现出现非数字的情况的);所以有了如下结果:

/(?:\d+@?)+.\w+/的匹配结果

实际上这种已经不符合第一种邮箱格式了,为了排除这种可能,我不得不考虑在首位加个符号^以标识邮箱是以数字开始输入的:/^(?:\d+@?)+.\w+/

4)然后我发现,上述表达式有一个严重的bug - 对于符号“.”没有进行转义

于是出现了以下错误的(❌)匹配结果:

没有转义的元字符.引发的异常匹配-1

那么上述错误是怎么发生的呢?

您可以尝试从结果一步步逆推回去。当然,我当前也是如此做的,比方说111222335556666@这个数字部分说明第一部分的\d+是生效了的,同时元字符?对其前面的子表达式(即@部分)可出现0次或1次的表述,使得结果里第一部分数字后跟着一个@;至此第一部分的数字和@符号匹配完毕;

紧接着应该匹配第二部分的数字,从结果可知,第二部分的\d+匹配到了163,@没出现是因为元字符?标识它可以不出现。

那么上述异常结果中,wwww是怎么来的呢?

其原因是元字符.没有做转义,而元字符.的含义是匹配除换行符和回车符之外的任意单个字符。从结果来看,由于元字符.紧跟在匹配数字的正则子表达式之后,于是它顺利匹配到了163之后的单个字符w;而剩下的3个www则是由\w+完成的匹配。

上述错误得出的教训:1,尽可能熟悉每个元字符的含义;2,该转义的字符千万别漏了。

上述错误修正后的结果:/(?:\d+@?)+\.\w+/

上述错误的同类结果:

没有转义的元字符.引发的异常匹配-2

它出现的原因大体同上,但上述结果的出现有一个地方需要重点说明下:正则表达式默认是贪婪匹配模式,这意味着,(假如您大致懂一点回溯的内容的话),一次能到终点的操作,它绝对不会回溯一次另外选一条路走!这一点很重要!

这导致了上述表达式中(?:\d+@?)+这个部分只执行了一次,得到了结果“111222335556666@”;然后紧跟其后的元字符.匹配到了w;然后由于元字符\w表述了字母、数字、下划线三种概念,于是它跟元字符+一起,匹配到了最后的www163 部分。关于上述结果的验证过程,可以考虑将正则的\w+部分去掉,您会发现,结果是“111222335556666@w”。

也许您可以试着分析下如下两个字符串的匹配结果:

[email protected]

[email protected]

5)然后我发现,第4步中得到的结果还有瑕疵 - \w 除了字母,还能匹配数字和下划线

于是下边的错误也就发生了:

\w+并不适合用来匹配纯字母组成的域名部分

为了修正错误:我将表达式调整为/(?:\d+@?)+\.[a-zA-Z]+/(当然,假设有人把域名写成COm这种形式,我建议还是整体对邮箱字符串做一下toUpperCase或者toLowerCase比较好!虽然是可以做进一步拆分校验,但严格来说,这并不属于校验不合法的范畴)

3.3,数字、字母 + 下划线 + @ + 数字|字母 + .com:

相关元字符:

\w  -  表示字母、数字、下划线

+   -  表示该符号(即符号+)前出现的子表达式需要至少出现1次;

*   -   表示该符号前出现的子表达式需要至少出现0次

? -   表示该字符前出现的子表达式可以出现0次或1次

^   -   略

.   -    略

经过上述3.1部分的啰里吧嗦,我想初步的正则表达式并不难配,对吧。

比如:/^(?:\w+@?)+\.[a-zA-Z]+/

接着,请跟我一起来拆解下上述的表达式:

1)^(?:\w+@?)+:表述了我想匹配以\w开头,且形如:zhangsan_1@163(qq)这样格式的字符串

2)\.:表述匹配普通字符.

3)[a-zA-Z]+: 最后一部分\w+表述我想匹配最后的域名部分(当然,形如.com.cn暂时不在讨论范围内)

通过拆解表达式,您可以发现,上述部分出现了3.2中第5步的错误,即\w并不光匹配字母、数字,还匹配下划线。

而下划线出现在第一部分,即@符号之前,可以说是符合本回合邮箱构造规则;但是,若出现在@符合之后的第二部分,那就大为不妥了,而上述表达式显然,会出现以下匹配结果:

/^(?:\w+@?)+\.\w+/表达式的异常匹配-1

/^(?:\w+@?)+\.\w+/表达式的异常匹配-2

由于上述的表达式对于第二部分内容(@字符之后,.字符之前),匹配的并不尽如人意。所以子表达式“^(?:\w+@?)+”需要对第二部分的匹配进行优化。

既然问题出在第二部分,那么意味着,我在3.2中分析时,对@符号前后子表达式的整合(即将xx@xx整合为(xx@?)+这种形式)就不攻自破了。

那么,对于第二部分的匹配期望,我现在需要构造一个正则表达式,使得能且仅能匹配(纯数字或纯字母表达式的)其中一种情况,即要么匹配类似ww这样的字符串,要么匹配111这样的字符串,其他字符串暂且假定非法。

于是,您会发现,我在3.1中已经引导您做过类似的校验。然后,您可能会犯我之前犯过的错误,即简单粗暴地将其添加到正则表达式中,形成这样的式子:/^\w+@(?:^\d+$|^[a-zA-Z]+$)\.[a-zA-Z]+/;

然后您会发现,这下不仅仅是错误的字符串无法通过校验,正确的字符串也不行了!

于是,我希望您能跟我一起来重温一下元字符^和元字符$的概念:前者匹配输入的起始位置,后者匹配输入的结束位置;所以,这就是我在3.1中加入起始和结束元字符可以生效,而在3.3中失效的原因(因为对于输入者而言,可以人为的理解某一段输入值的开始和结束位置,但对于程序而言,字符串的起始和结束位置是相对于整体而言的,而非局部的某个子串。)

基于上述反思,较为合理的一个正则表达式为:/^\w+@(?:\d+|[a-zA-Z]+)\.[a-zA-Z]+/

3.4,待续......

你可能感兴趣的:(php邮箱正则下划线)