完全兼容RFC5321和5322的PHP PCRE regex

时间:2018-11-30 18:57:42

标签: php regex email pcre

我正在尝试创建一个PHP PCRE正则表达式,该正则表达式(几乎)与RFC5321和5322完全兼容,以测试email addresses。我唯一不需要的是(注释)部分。我在这里已经看到了其他一些尝试,但是当我对它们进行测试时,它们并不能全部工作。

我一直在研究一个非常接近的东西:

 ^(([\w \!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~\.]{1,64})|("[\w \!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~\.]{1,64}"))@(([\w\-]*\.?[\w\-]*)|(\[\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\])|(\[IPv6:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}\]))$

要分解它:

本地部分:

(

最多匹配64个允许的字符

   ([\w \!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~\.]{1,64})
    |

或匹配带引号的字符串中的相同字符集:

   ("[\w \!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~\.]{1,64}")
)

结束本地部分。

匹配@符号

@

匹配域部分:

(

使用允许的字符匹配域部分:

   ([\w\-]*\.?[\w\-]*)

或ipv4(它不会检查以确保它们是<255-将在其他地方处理)

   (\[\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\])

或ipv6

   (\[IPv6:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}\])

)

唯一缺少的是能够检查引号局部部分之外的多个连续的。(句点)。我使用自己的一些测试以及regex101.com上的测试在wikipedia article about email addresses和下面的所有地址上进行了测试:

bob@smith.com
bob.smith@smith.com
bob-smith@smith.com
bob-smith@bob-smith.com
b0b!-...smith@smith.com <-DOES NOT VALIDATE CORRECTLY - MULTIPLE .'s
bob&smith@smith.com
"bob..smith"@smith.com

simple@example.com
very.common@example.com
disposable.style.email.with+symbol@example.com
other.email-with-hyphen@example.com
fully-qualified-domain@example.com
user.name+tag+sorting@example.com
x@example.com
example-indeed@strange-example.com
admin@mailserver1
example@s.example
" "@example.org
"john..doe"@example.org

Abc.example.com
A@b@c@example.com
a"b(c)d,e:f;g<h>i[j\k]l@example.com
just"not"right@example.com
this is"not\allowed@example.com
this\ still\"not\\allowed@example.com
1234567890123456789012345678901234567890123456789012345678901234+x@example.com
john..doe@example.com  <-DOES NOT VALIDATE CORRECTLY - MULTIPLE .'s
john.doe@example..com

我尝试使用先行断言和后向断言来测试连续的时间段,但是我无法弄清楚。我认为这是唯一缺失的内容(除了注释,对于我而言,这不是必需的)。

有没有一种方法可以检查那些不会改变我目前所拥有的时间段的周期,或者是否需要一种不同的方法?

如果我错过了其他任何事情,请告诉我。

谢谢。

2 个答案:

答案 0 :(得分:1)

我会推荐您read this。足以说写一个可以100%工作的正则表达式是不可能的。

我写了一个非Regex实现here。如果您将其移植到php并在我的github页面上提交问题,或向我发送电子邮件(在我的github页面上列出),我将很高兴链接到它。

unit tests可以看出,它已经足够全面,可以使用EAI地址了。

答案 1 :(得分:1)

您可以在(?!("[^"]*"|[^"])*\.{2})之后添加^

请参见regex demo

如果在当前位置的右边立即有(?!("[^"]*"|[^"])*\.{2})否定前瞻,则匹配失败

  • ("[^"]*"|[^"])*-出现0次或多次",后跟0+个非"的字符,然后为""以外的任何字符< / li>
  • \.{2}-两个连续的点。