使用ASP.NET 3.5验证进行电子邮件格式验证的最佳正则表达式

时间:2009-06-01 21:26:02

标签: asp.net regex

我使用以下两种正则表达式来测试带有ASP.NET验证控件的有效电子邮件表达式。我想知道从性能的角度来看哪个是更好的表达,或者有人有更好的表达。

 - \w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
 - ^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$

我正在尝试避免BCL Team Blog中描述的“指数缓慢表达”问题。

更新

根据反馈,我最终创建了一个测试电子邮件是否有效的功能:

Public Function IsValidEmail(ByVal emailString As String, Optional ByVal isRequired As Boolean = False) As Boolean
    Dim emailSplit As String()
    Dim isValid As Boolean = True
    Dim localPart As String = String.Empty
    Dim domainPart As String = String.Empty
    Dim domainSplit As String()
    Dim tld As String

    If emailString.Length >= 80 Then
        isValid = False
    ElseIf emailString.Length > 0 And emailString.Length < 6 Then
        'Email is too short
        isValid = False
    ElseIf emailString.Length > 0 Then
        'Email is optional, only test value if provided
        emailSplit = emailString.Split(CChar("@"))

        If emailSplit.Count <> 2 Then
            'Only 1 @ should exist
            isValid = False
        Else
            localPart = emailSplit(0)
            domainPart = emailSplit(1)
        End If

        If isValid = False OrElse domainPart.Contains(".") = False Then
            'Needs at least 1 period after @
            isValid = False
        Else
            'Test Local-Part Length and Characters
            If localPart.Length > 64 OrElse ValidateString(localPart, ValidateTests.EmailLocalPartSafeChars) = False OrElse _
               localPart.StartsWith(".") OrElse localPart.EndsWith(".") OrElse localPart.Contains("..") Then
                isValid = False
            End If

            'Validate Domain Name Portion of email address
            If isValid = False OrElse _
               ValidateString(domainPart, ValidateTests.HostNameChars) = False OrElse _
               domainPart.StartsWith("-") OrElse domainPart.StartsWith(".") OrElse domainPart.Contains("..") Then
                isValid = False
            Else
                domainSplit = domainPart.Split(CChar("."))
                tld = domainSplit(UBound(domainSplit))

                ' Top Level Domains must be at least two characters
                If tld.Length < 2 Then
                    isValid = False
                End If
            End If
        End If
    Else
        'If no value is passed review if required
        If isRequired = True Then
            isValid = False
        Else
            isValid = True
        End If
    End If

    Return isValid
End Function

注意:

  • IsValidEmail对RFC允许的字符限制性更强,但不测试这些字符的所有可能无效使用

9 个答案:

答案 0 :(得分:12)

如果您想知道为什么这个问题会产生如此少的活动,那是因为在您开始考虑性能之前还有许多其他问题需要处理。其中最重要的是你是否应该使用正则表达式来验证电子邮件地址 - 而且你不应该达成共识。它比大多数人想象的要复杂得多,而且无论如何都可能毫无意义。

另一个问题是你的两个正则表达式在它们可以匹配的字符串种类上有很大差异。例如,第二个锚定在两端,但第一个不是;它会匹配“>>>>foo@bar.com<<<<”,因为它看起来像嵌入其中的电子邮件地址。也许框架强制正则表达式匹配整个字符串,但如果是这样的话,为什么第二个锚定?

另一个区别是第一个正则表达式始终使用\w,而第二个正则表达式在许多地方使用[0-9a-zA-Z]。在大多数正则表达式中,\w除了字母和数字之外还匹配下划线,但在某些(包括.NET)中,它还匹配来自Unicode已知的每个书写系统的字母和数字。

还有许多其他差异,但这是学术上的;这些正则表达式都不是很好。有关该主题的详细讨论,请参阅here,以及更好的正则表达式。

回到原来的问题,我没有看到这些正则表达式的性能问题。除了BCL博客条目中引用的嵌套量词反模式之外,您还应该注意正则表达式的两个或多个相邻部分可以匹配相同字符集的情况 - 例如,

([A-Za-z]+|\w+)@

在你发布的任何一个正则表达式中都没有这样的东西。由量词控制的零件总是被其他未量化的零件分解。两个正则表达式都会经历一些可避免的回溯,但有很多比性能更好的理由拒绝它们。

编辑:所以第二个正则表达式 受到灾难性的回溯;在拍摄我的嘴之前,我应该彻底测试它。仔细看看那个正则表达式,我不明白为什么你需要在第一部分中使用外部星号:

[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*

所有这一切都是为了确保第一个和最后一个字符是字母数字,同时允许其间有一些额外的字符。这个版本做了同样的事情,但是当不可能匹配时它会更快失败:

[0-9a-zA-Z][-.\w]*[0-9a-zA-Z]

这可能足以消除回溯问题,但你也可以通过使用原子组使“@”之后的部分更有效:

(?>(?:[0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+)[a-zA-Z]{2,9}

换句话说,如果你已经匹配所有可能的带有尾随点的域组件的子串,并且下一部分看起来不像TLD,那么就不要去追溯了。您必须放弃的第一个字符是最后一个点,您知道[a-zA-Z]{2,9}将与之不匹配。

答案 1 :(得分:8)

我们使用此RegEx已经在内部测试了150万个地址。它正确地识别出超过98%的我们的,但有些格式我知道它会出错。

^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$

我们还确保数据中没有EOL字符,因为EOL可以伪造此RegEx。我们的职能:

Public Function IsValidEmail(ByVal strEmail As String) As Boolean
    ' Check An eMail Address To Ensure That It Is Valid
    Const cValidEmail = "^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$"   ' 98% Of All Valid eMail Addresses
    IsValidEmail = False
    ' Take Care Of Blanks, Nulls & EOLs
    strEmail = Replace(Replace(Trim$(strEmail & " "), vbCr, ""), vbLf, "")
    ' Blank eMail Is Invalid
    If strEmail = "" Then Exit Function
    ' RegEx Test The eMail Address
    Dim regEx As New System.Text.RegularExpressions.Regex(cValidEmail)
    IsValidEmail = regEx.IsMatch(strEmail)
End Function

答案 2 :(得分:2)

我是新手,但我尝试了以下内容,它似乎将“.xxx”限制为只有两次或更少,在符号'@'之后。

^([a-zA-Z0-9]+[a-zA-Z0-9._%-]*@(?:[a-zA-Z0-9-])+(\.+[a-zA-Z]{2,4}){1,2})$

注意:我必须用'\\'替换单个'\',因为我在R中使用此reg expr。

答案 3 :(得分:1)

这些不会根据email address RFC检查所有允许的电子邮件地址。

答案 4 :(得分:1)

我让MS为我做的工作:

Public Function IsValidEmail(ByVal emailString As String) As Boolean
    Dim retval As Boolean = True
    Try
        Dim address As New System.Net.Mail.MailAddress(emailString)
    Catch ex As Exception
        retval = False
    End Try
    Return retval
End Function

答案 5 :(得分:1)

对于服务器端验证,我发现Phil Haack的解决方案是更好的解决方案之一。他的尝试是坚持RFC:

string pattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
            + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
            + @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$";

Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
return regex.IsMatch(emailAddress);

详细说明: http://blog.degree.no/2013/01/email-validation-finally-a-net-regular-expression-that-works/

答案 6 :(得分:0)

只是为了贡献,我正在使用这个正则表达式。

^([a-zA-Z0-9]+[a-zA-Z0-9._%-]*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4})$

答案 7 :(得分:0)

关于它的事情是规范随着引入的每个域扩展而变化。

你坐在这里修改你的正则表达式,测试,测试,测试和更多测试。你终于得到了你的想法&#34;是准确的然后规范更改...您更新您的正则表达式以考虑新的要求是什么..

然后有人输入aa@aa.aa并且您已完成所有工作?它走过你喜欢的正则表达式。真可惜!

你也可以只检查一个@和一个&#34;。&#34;然后继续前进。我向你保证,如果他们不想放弃,你就不会收到某人的电子邮件。你会得到他们从未检查过的垃圾或他们的hotmail帐户,而且不会关心它们。

我在很多情况下都看到过这种情况非常糟糕而客户打电话是因为他们自己的电子邮件地址被拒绝了,因为正在制作一个糟糕的正则表达式检查。如上所述,甚至都没有尝试过。

答案 8 :(得分:0)

TextBox: -

<asp:TextBox ID="txtemail" runat="server" CssClass="form-control pantxt" Placeholder="Enter Email Address"></asp:TextBox>

必填提交验证人:

<asp:RequiredFieldValidator ID="RequiredFieldValidator9" runat="server" ControlToValidate="txtemail" ErrorMessage="Required"></asp:RequiredFieldValidator>

电子邮件验证的正则表达式:

<asp:RegularExpressionValidator ID="validateemail" runat="server" ControlToValidate="txtemail" ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" ErrorMessage="Invalid Email"></asp:RegularExpressionValidator>

将此正则表达式用于asp.net中的电子邮件验证