多年来,我慢慢地开发了一个正则表达式,它可以正确验证大多数电子邮件地址,假设它们不使用IP地址作为服务器部分。
我在几个PHP程序中使用它,而且大多数时候都可以使用。然而,不时有人与我联系,他们对使用它的网站有问题,我最终不得不做出一些调整(最近我意识到我不允许四个字符的TLD)。
你有或见过验证电子邮件的最佳正则表达式是什么?
我见过几种使用函数的解决方案,这些函数使用了几个较短的表达式,但我宁愿在简单函数中使用一个长的复杂表达式,而不是在更复杂的函数中使用几个短表达式。
多年来,我慢慢地开发了一个正则表达式,它可以正确验证大多数电子邮件地址,假设它们不使用IP地址作为服务器部分。
我在几个PHP程序中使用它,而且大多数时候都可以使用。然而,不时有人与我联系,他们对使用它的网站有问题,我最终不得不做出一些调整(最近我意识到我不允许四个字符的TLD)。
你有或见过验证电子邮件的最佳正则表达式是什么?
我见过几种使用函数的解决方案,这些函数使用了几个较短的表达式,但我宁愿在简单函数中使用一个长的复杂表达式,而不是在更复杂的函数中使用几个短表达式。
当前回答
世界上最流行的博客平台WordPress使用此功能验证电子邮件地址。。。
但他们是通过多个步骤来实现的。
使用此函数中提到的正则表达式时,您不必再担心。。。
这是函数。。。
/**
* Verifies that an email is valid.
*
* Does not grok i18n domains. Not RFC compliant.
*
* @since 0.71
*
* @param string $email Email address to verify.
* @param boolean $deprecated Deprecated.
* @return string|bool Either false or the valid email address.
*/
function is_email( $email, $deprecated = false ) {
if ( ! empty( $deprecated ) )
_deprecated_argument( __FUNCTION__, '3.0' );
// Test for the minimum length the email can be
if ( strlen( $email ) < 3 ) {
return apply_filters( 'is_email', false, $email, 'email_too_short' );
}
// Test for an @ character after the first position
if ( strpos( $email, '@', 1 ) === false ) {
return apply_filters( 'is_email', false, $email, 'email_no_at' );
}
// Split out the local and domain parts
list( $local, $domain ) = explode( '@', $email, 2 );
// LOCAL PART
// Test for invalid characters
if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
}
// DOMAIN PART
// Test for sequences of periods
if ( preg_match( '/\.{2,}/', $domain ) ) {
return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
}
// Test for leading and trailing periods and whitespace
if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
}
// Split the domain into subs
$subs = explode( '.', $domain );
// Assume the domain will have at least two subs
if ( 2 > count( $subs ) ) {
return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
}
// Loop through each sub
foreach ( $subs as $sub ) {
// Test for leading and trailing hyphens and whitespace
if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
}
// Test for invalid characters
if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
}
}
// Congratulations your email made it!
return apply_filters( 'is_email', $email, $email, null );
}
其他回答
我从不麻烦用自己的正则表达式创建,因为很可能其他人已经提出了更好的版本。我总是使用regexlib来找到一个我喜欢的。
我不相信bortzmeyer所说的“语法(RFC 5322中指定的)太复杂了”(无法用正则表达式处理)。
这是语法(来自3.4.1。添加规范规范):
addr-spec = local-part "@" domain
local-part = dot-atom / quoted-string / obs-local-part
domain = dot-atom / domain-literal / obs-domain
domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
dtext = %d33-90 / ; Printable US-ASCII
%d94-126 / ; characters not including
obs-dtext ; "[", "]", or "\"
假设点原子、带引号的字符串、obs局部部分、obs域本身是正则语言,这是一个非常简单的语法。只需将addr-spec产品中的本地部分和域替换为它们各自的产品,您就拥有了一种可直接转换为正则表达式的正则语言。
我也有类似的愿望:希望快速检查电子邮件地址中的语法,而不要过分使用电子邮件发送实用程序(邮件::RFC822::地址答案显然是正确的答案)。我同意这个(我是一个POSIX正则表达式的人,所以我通常不会使用PCRE中的\d等,因为它们让我看不清楚):
preg_match("_^[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*@[0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?)*\$_", $adr)
这是RFC正确的,但它明确排除了过时的表单以及直接IP地址(IP地址和传统IP地址),而该实用程序的目标组中的某些人(主要是:在IRC上的#sendmail中打扰我们的人)通常不希望或不需要这些地址。
IDN(国际化域名)明确不在电子邮件范围内:地址如“foo@cäcilenchor bonn.de“必须写”foo@xn--ccilienchor-bonn-vnb.de而在网络上(这包括HTML中的mailto:links和这样的乐趣),只允许GUI向用户显示(并接受然后转换)这样的名称。
这是我使用的PHP代码。我选择这个解决方案是出于“误报比误报好”的精神,正如这里的另一位评论者所说的,并考虑到保持您的响应时间并降低服务器负载。。。当正则表达式可以消除大多数简单的用户错误时,真的不需要浪费服务器资源。如果你愿意,你可以随时通过发送测试邮件来跟进。
function validateEmail($email) {
return (bool) stripos($email,'@');
}
在Perl 5.10或更高版本中很容易:
/(?(DEFINE)
(?<address> (?&mailbox) | (?&group))
(?<mailbox> (?&name_addr) | (?&addr_spec))
(?<name_addr> (?&display_name)? (?&angle_addr))
(?<angle_addr> (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
(?<group> (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ;
(?&CFWS)?)
(?<display_name> (?&phrase))
(?<mailbox_list> (?&mailbox) (?: , (?&mailbox))*)
(?<addr_spec> (?&local_part) \@ (?&domain))
(?<local_part> (?&dot_atom) | (?"ed_string))
(?<domain> (?&dot_atom) | (?&domain_literal))
(?<domain_literal> (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
\] (?&CFWS)?)
(?<dcontent> (?&dtext) | (?"ed_pair))
(?<dtext> (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])
(?<atext> (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
(?<atom> (?&CFWS)? (?&atext)+ (?&CFWS)?)
(?<dot_atom> (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
(?<dot_atom_text> (?&atext)+ (?: \. (?&atext)+)*)
(?<text> [\x01-\x09\x0b\x0c\x0e-\x7f])
(?<quoted_pair> \\ (?&text))
(?<qtext> (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
(?<qcontent> (?&qtext) | (?"ed_pair))
(?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
(?&FWS)? (?&DQUOTE) (?&CFWS)?)
(?<word> (?&atom) | (?"ed_string))
(?<phrase> (?&word)+)
# Folding white space
(?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
(?<ctext> (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
(?<ccontent> (?&ctext) | (?"ed_pair) | (?&comment))
(?<comment> \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
(?<CFWS> (?: (?&FWS)? (?&comment))*
(?: (?:(?&FWS)? (?&comment)) | (?&FWS)))
# No whitespace control
(?<NO_WS_CTL> [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])
(?<ALPHA> [A-Za-z])
(?<DIGIT> [0-9])
(?<CRLF> \x0d \x0a)
(?<DQUOTE> ")
(?<WSP> [\x20\x09])
)
(?&address)/x