完全兼容 RFC5321 和 5322 PHP PCRE 正则表达式

fully RFC5321- and 5322-compatible PHP PCRE regex

我正在尝试创建一个(几乎)与 RFC5321 和 5322 完全兼容的 PHP PCRE 正则表达式来测试 email addresses。我唯一不需要的是 (comment) 部分。我已经在此处看到其他一些尝试,但是当我 运行 测试它们时,它们并不都有效。

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

 ^(([\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 vs. all the addresses below using some of my own tests and the tests on the 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

我试图使用先行断言和后行断言来测试连续的时间段,但我无法弄清楚。我认为这是它唯一缺少的东西(除了评论,就我的目的而言,评论不是必需的)。

有没有一种方法可以检查不会改变我目前拥有太多东西的时期,或者是否需要不同的方法?

如果我遗漏了什么,请告诉我。

谢谢。

我会推荐你​​ read this。可以这么说,编写一个 100% 有效的正则表达式是不可能的。

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

unit tests 中可以看出,它足够全面,也可以使用 EAI 地址。

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

参见regex demo

如果紧挨着当前位置的右侧有

,则(?!("[^"]*"|[^"])*\.{2}) 否定先行匹配失败
  • ("[^"]*"|[^"])* - " 出现 0 次或多次,后跟 " 以外的 0+ 个字符,然后是 " 或 [=14= 以外的任何字符]
  • \.{2} - 两个连续的点。