验证字符串是否是有效的电子邮件地址的最优雅的代码是什么?


当前回答

基于@Cogwheel的回答,我想分享一个修改后的解决方案,适用于SSIS和“脚本组件”:

Place the "Script Component" into your Data Flow connect and then open it. In the section "Input Columns" set the field that contains the E-Mail Adresses to "ReadWrite" (in the example 'fieldName'). Switch back to the section "Script" and click on "Edit Script". Then you need to wait after the code opens. Place this code in the right method: public override void Input0_ProcessInputRow(Input0Buffer Row) { string email = Row.fieldName; try { System.Net.Mail.MailAddress addr = new System.Net.Mail.MailAddress(email); Row.fieldName= addr.Address.ToString(); } catch { Row.fieldName = "WRONGADDRESS"; } }

然后,您可以使用条件分割过滤掉所有无效记录或任何您想做的事情。

其他回答

这是一个老问题,但我在SO上找到的所有答案,包括最近的答案,都与这个问题类似。然而,在。net 4.5 / MVC 4中,你可以通过从System.ComponentModel中添加[EmailAddress]注释来向表单添加电子邮件地址验证。DataAnnotations,所以我想知道为什么我不能只使用。net的内置功能。

这似乎是可行的,而且在我看来是相当优雅的:

using System.ComponentModel.DataAnnotations;

class ValidateSomeEmails
{
    static void Main(string[] args)
    {
        var email = new EmailAddressAttribute();
        email.IsValid("someone@somewhere.com");         //true
        email.IsValid("someone@somewhere.co.uk");       //true
        email.IsValid("someone+tag@somewhere.net");     //true
        email.IsValid("futureTLD@somewhere.fooo");      //true
        
        email.IsValid("fdsa");                          //false
        email.IsValid("fdsa@");                         //false
        email.IsValid("fdsa@fdsa");                     //false
        email.IsValid("fdsa@fdsa.");                    //false

        //one-liner
        if (new EmailAddressAttribute().IsValid("someone@somewhere.com")) 
            return true;
    }
}

我根据维基百科的规则和样本地址创建了一个电子邮件地址验证程序。对于那些不介意多看一点代码的人,这里。说实话,我不知道电子邮件地址规范中有这么多疯狂的规则。我没有完全验证主机名或ipaddress,但它仍然通过了维基百科上的所有测试用例。

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace EmailValidateUnitTests
{
    [TestClass]
    public class EmailValidationUnitTests
    {
        [TestMethod]
        public void TestEmailValidate()
        {
            // Positive Assertions
            Assert.IsTrue("prettyandsimple@example.com".IsValidEmailAddress());
            Assert.IsTrue("very.common@example.com".IsValidEmailAddress());
            Assert.IsTrue("disposable.style.email.with+symbol@example.com".IsValidEmailAddress());
            Assert.IsTrue("other.email-with-dash@example.com".IsValidEmailAddress());
            Assert.IsTrue("\"much.more unusual\"@example.com".IsValidEmailAddress());
            Assert.IsTrue("\"very.unusual.@.unusual.com\"@example.com".IsValidEmailAddress()); //"very.unusual.@.unusual.com"@example.com
            Assert.IsTrue("\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com".IsValidEmailAddress()); //"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com
            Assert.IsTrue("admin@mailserver1".IsValidEmailAddress());
            Assert.IsTrue("#!$%&'*+-/=?^_`{}|~@example.org".IsValidEmailAddress());
            Assert.IsTrue("\"()<>[]:,;@\\\\\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org".IsValidEmailAddress()); //"()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a"@example.org
            Assert.IsTrue("\" \"@example.org".IsValidEmailAddress()); //" "@example.org (space between the quotes)
            Assert.IsTrue("example@localhost".IsValidEmailAddress());
            Assert.IsTrue("example@s.solutions".IsValidEmailAddress());
            Assert.IsTrue("user@com".IsValidEmailAddress());
            Assert.IsTrue("user@localserver".IsValidEmailAddress());
            Assert.IsTrue("user@[IPv6:2001:db8::1]".IsValidEmailAddress());
            Assert.IsTrue("user@[192.168.2.1]".IsValidEmailAddress());
            Assert.IsTrue("(comment and stuff)joe@gmail.com".IsValidEmailAddress());
            Assert.IsTrue("joe(comment and stuff)@gmail.com".IsValidEmailAddress());
            Assert.IsTrue("joe@(comment and stuff)gmail.com".IsValidEmailAddress());
            Assert.IsTrue("joe@gmail.com(comment and stuff)".IsValidEmailAddress());

            // Failure Assertions
            Assert.IsFalse("joe(fail me)smith@gmail.com".IsValidEmailAddress());
            Assert.IsFalse("joesmith@gma(fail me)il.com".IsValidEmailAddress());
            Assert.IsFalse("joe@gmail.com(comment and stuff".IsValidEmailAddress());
            Assert.IsFalse("Abc.example.com".IsValidEmailAddress());
            Assert.IsFalse("A@b@c@example.com".IsValidEmailAddress());
            Assert.IsFalse("a\"b(c)d,e:f;g<h>i[j\\k]l@example.com".IsValidEmailAddress()); //a"b(c)d,e:f;g<h>i[j\k]l@example.com
            Assert.IsFalse("just\"not\"right@example.com".IsValidEmailAddress()); //just"not"right@example.com
            Assert.IsFalse("this is\"not\\allowed@example.com".IsValidEmailAddress()); //this is"not\allowed@example.com
            Assert.IsFalse("this\\ still\\\"not\\\\allowed@example.com".IsValidEmailAddress());//this\ still\"not\\allowed@example.com
            Assert.IsFalse("john..doe@example.com".IsValidEmailAddress());
            Assert.IsFalse("john.doe@example..com".IsValidEmailAddress());
            Assert.IsFalse(" joe@gmail.com".IsValidEmailAddress());
            Assert.IsFalse("joe@gmail.com ".IsValidEmailAddress());
        }
    }

    public static class ExtensionMethods
    {
        private const string ValidLocalPartChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'*+-/=?^_`{|}~";
        private const string ValidQuotedLocalPartChars = "(),:;<>@[]. ";
        private const string ValidDomainPartChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-:";

        private enum EmailParseMode
        {
            BeginLocal, Local, QuotedLocalEscape, QuotedLocal, QuotedLocalEnd, LocalSplit, LocalComment,
            At,
            Domain, DomainSplit, DomainComment, BracketedDomain, BracketedDomainEnd
        };

        public static bool IsValidEmailAddress(this string s)
        {
            bool valid = true;

            bool hasLocal = false, hasDomain = false;
            int commentStart = -1, commentEnd = -1;
            var mode = EmailParseMode.BeginLocal;
            for (int i = 0; i < s.Length; i++)
            {
                char c = s[i];
                if (mode == EmailParseMode.BeginLocal || mode == EmailParseMode.LocalSplit)
                {
                    if (c == '(') { mode = EmailParseMode.LocalComment; commentStart = i; commentEnd = -1; }
                    else if (c == '"') { mode = EmailParseMode.QuotedLocal; }
                    else if (ValidLocalPartChars.IndexOf(c) >= 0) { mode = EmailParseMode.Local; hasLocal = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.LocalComment)
                {
                    if (c == ')')
                    {
                        mode = EmailParseMode.Local; commentEnd = i;
                        // comments can only be at beginning and end of parts...
                        if (commentStart != 0 && ((commentEnd + 1) < s.Length) && s[commentEnd + 1] != '@') { valid = false; break; }
                    }
                }
                else if (mode == EmailParseMode.Local)
                {
                    if (c == '.') mode = EmailParseMode.LocalSplit;
                    else if (c == '@') mode = EmailParseMode.At;
                    else if (c == '(') { mode = EmailParseMode.LocalComment; commentStart = i; commentEnd = -1; }
                    else if (ValidLocalPartChars.IndexOf(c) >= 0) { hasLocal = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.QuotedLocal)
                {
                    if (c == '"') { mode = EmailParseMode.QuotedLocalEnd; }
                    else if (c == '\\') { mode = EmailParseMode.QuotedLocalEscape; }
                    else if (ValidLocalPartChars.IndexOf(c) >= 0 || ValidQuotedLocalPartChars.IndexOf(c) >= 0) { hasLocal = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.QuotedLocalEscape)
                {
                    if (c == '"' || c == '\\') { mode = EmailParseMode.QuotedLocal; hasLocal = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.QuotedLocalEnd)
                {
                    if (c == '.') { mode = EmailParseMode.LocalSplit; }
                    else if (c == '@') mode = EmailParseMode.At;
                    else if (c == '(') { mode = EmailParseMode.LocalComment; commentStart = i; commentEnd = -1; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.At)
                {
                    if (c == '[') { mode = EmailParseMode.BracketedDomain; }
                    else if (c == '(') { mode = EmailParseMode.DomainComment; commentStart = i; commentEnd = -1; }
                    else if (ValidDomainPartChars.IndexOf(c) >= 0) { mode = EmailParseMode.Domain; hasDomain = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.DomainComment)
                {
                    if (c == ')')
                    {
                        mode = EmailParseMode.Domain;
                        commentEnd = i;
                        // comments can only be at beginning and end of parts...
                        if ((commentEnd + 1) != s.Length && (commentStart > 0) && s[commentStart - 1] != '@') { valid = false; break; }
                    }
                }
                else if (mode == EmailParseMode.DomainSplit)
                {
                    if (ValidDomainPartChars.IndexOf(c) >= 0) { mode = EmailParseMode.Domain; hasDomain = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.Domain)
                {
                    if (c == '(') { mode = EmailParseMode.DomainComment; commentStart = i; commentEnd = -1; }
                    else if (c == '.') { mode = EmailParseMode.DomainSplit; }
                    else if (ValidDomainPartChars.IndexOf(c) >= 0) { hasDomain = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.BracketedDomain)
                {
                    if (c == ']') { mode = EmailParseMode.BracketedDomainEnd; }
                    else if (c == '.' || ValidDomainPartChars.IndexOf(c) >= 0) { hasDomain = true; }
                    else { valid = false; break; }
                }
                else if (mode == EmailParseMode.BracketedDomain)
                {
                    if (c == '(') { mode = EmailParseMode.DomainComment; commentStart = i; commentEnd = -1; }
                    else { valid = false; break; }
                }
            }
            bool unfinishedComment = (commentEnd == -1 && commentStart >= 0);

            return hasLocal && hasDomain && valid && !unfinishedComment;
        }
    }
}

正如在许多回答中提到的,电子邮件地址的领域是复杂的。在这种情况下,我强烈反对使用正则表达式。那些匹配(大多数)用例的异常复杂,难以读取,因此也难以维护。此外,它们仍然难以支持所有病例,而且速度缓慢。

微软的EmailAddress类在这方面有所帮助,但我认为也不是完美的。在几年前的一个开源项目中,我尝试使用定制的EmailParser。

在[EmailAddress]https://github.com/Qowaiv/Qowaiv/blob/master/src/Qowaiv/EmailAddress.cs中使用。

通过使用这种方法,不仅可以验证电子邮件地址,还可以清除显示名称的多种格式,去掉mailto:-前缀,并根据ip地址规范化域字面量,并将所有内容小写(注意,本地部分是大小写敏感的)。

你的解决方案应该支持的场景(上面提到的就是):

[TestCase(null)]
[TestCase("")]
[TestCase("..@test.com")]
[TestCase(".a@test.com")]
[TestCase("ab@sd@dd")]
[TestCase(".@s.dd")]
[TestCase("ab@988.120.150.10")]
[TestCase("ab@120.256.256.120")]
[TestCase("ab@120.25.1111.120")]
[TestCase("ab@[188.120.150.10")]
[TestCase("ab@188.120.150.10]")]
[TestCase("ab@[188.120.150.10].com")]
[TestCase("a@b.-de.cc")]
[TestCase("a@bde-.cc")]
[TestCase("a@bde.c-c")]
[TestCase("a@bde.cc.")]
[TestCase("ab@b+de.cc")]
[TestCase("a..b@bde.cc")]
[TestCase("_@bde.cc,")]
[TestCase("plainaddress")]
[TestCase("plain.address")]
[TestCase("@%^%#$@#$@#.com")]
[TestCase("@domain.com")]
[TestCase("Joe Smith &lt;email@domain.com&gt;")]
[TestCase("email.domain.com")]
[TestCase("email@domain@domain.com")]
[TestCase(".email@domain.com")]
[TestCase("email.@domain.com")]
[TestCase("email..email@domain.com")]
[TestCase("email@-domain.com")]
[TestCase("email@domain-.com")]
[TestCase("email@domain.com-")]
[TestCase("email@.domain.com")]
[TestCase("email@domain.com.")]
[TestCase("email@domain..com")]
[TestCase("email@111.222.333")]
[TestCase("email@111.222.333.256")]
[TestCase("email@[123.123.123.123")]
[TestCase("email@[123.123.123].123")]
[TestCase("email@123.123.123.123]")]
[TestCase("email@123.123.[123.123]")]
[TestCase("email@{leftbracket.com")]
[TestCase("email@rightbracket}.com")]
[TestCase("email@p|pe.com")]
[TestCase("isis@100%.nl")]
[TestCase("email@dollar$.com")]
[TestCase("email@r&amp;d.com")]
[TestCase("email@#hash.com")]
[TestCase("email@wave~tilde.com")]
[TestCase("email@exclamation!mark.com")]
[TestCase("email@question?mark.com")]
[TestCase("email@obelix*asterisk.com")]
[TestCase("email@grave`accent.com")]
[TestCase("email@colon:colon.com")]
[TestCase("email@caret^xor.com")]
[TestCase("email@=qowaiv.com")]
[TestCase("email@plus+.com")]
[TestCase("email@domain.com>")]
[TestCase("email( (nested) )@plus.com")]
[TestCase("email)mirror(@plus.com")]
[TestCase("email@plus.com (not closed comment")]
[TestCase("email(with @ in comment)plus.com")]
[TestCase(@"""Joe Smith email@domain.com")]
[TestCase(@"""Joe Smith' email@domain.com")]
[TestCase(@"""Joe Smith""email@domain.com")]
[TestCase("email@mailto:domain.com")]
[TestCase("mailto:mailto:email@domain.com")]
[TestCase("Display Name <email@plus.com> (after name with display)")]
[TestCase("ReDoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
public void IsInvalid(string email)
{
    Assert.IsFalse(EmailAddress.IsValid(email), email);
}

[TestCase("w@com")]
[TestCase("w.b.f@test.com")]
[TestCase("w.b.f@test.museum")]
[TestCase("a.a@test.com")]
[TestCase("ab@288.120.150.10.com")]
[TestCase("ab@188.120.150.10")]
[TestCase("ab@1.0.0.10")]
[TestCase("ab@120.25.254.120")]
[TestCase("ab@01.120.150.1")]
[TestCase("ab@88.120.150.021")]
[TestCase("ab@88.120.150.01")]
[TestCase("ab@[120.254.254.120]")]
[TestCase("local@2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
[TestCase("local@[2001:0db8:85a3:0000:0000:8a2e:0370:7334]")]
[TestCase("2@bde.cc")]
[TestCase("-@bde.cc")]
[TestCase("a2@bde.cc")]
[TestCase("a-b@bde.cc")]
[TestCase("ab@b-de.cc")]
[TestCase("a+b@bde.cc")]
[TestCase("f.f.f@bde.cc")]
[TestCase("ab_c@bde.cc")]
[TestCase("_-_@bde.cc")]
[TestCase("k.haak@12move.nl")]
[TestCase("K.HAAK@12MOVE.NL")]
[TestCase("email@domain.com")]
[TestCase("email@domain")]
[TestCase("あいうえお@domain.com")]
[TestCase("local@あいうえお.com")]
[TestCase("firstname.lastname@domain.com")]
[TestCase("email@subdomain.domain.com")]
[TestCase("firstname+lastname@domain.com")]
[TestCase("email@123.123.123.123")]
[TestCase("email@[123.123.123.123]")]
[TestCase("1234567890@domain.com")]
[TestCase("a@domain.com")]
[TestCase("a.b.c.d@domain.com")]
[TestCase("aap.123.noot.mies@domain.com")]
[TestCase("1@domain.com")]
[TestCase("email@domain-one.com")]
[TestCase("_______@domain.com")]
[TestCase("email@domain.topleveldomain")]
[TestCase("email@domain.co.jp")]
[TestCase("firstname-lastname@domain.com")]
[TestCase("firstname-lastname@d.com")]
[TestCase("FIRSTNAME-LASTNAME@d--n.com")]
[TestCase("first-name-last-name@d-a-n.com")]
[TestCase("{local{name{{with{@leftbracket.com")]
[TestCase("}local}name}}with{@rightbracket.com")]
[TestCase("|local||name|with|@pipe.com")]
[TestCase("%local%%name%with%@percentage.com")]
[TestCase("$local$$name$with$@dollar.com")]
[TestCase("&local&&name&with&$@amp.com")]
[TestCase("#local##name#with#@hash.com")]
[TestCase("~local~~name~with~@tilde.com")]
[TestCase("!local!!name!with!@exclamation.com")]
[TestCase("?local??name?with?@question.com")]
[TestCase("*local**name*with*@asterisk.com")]
[TestCase("`local``name`with`@grave-accent.com")]
[TestCase("^local^^name^with^@xor.com")]
[TestCase("=local==name=with=@equality.com")]
[TestCase("+local++name+with+@equality.com")]
[TestCase("Joe Smith <email@domain.com>")]
[TestCase("email@domain.com (joe Smith)")]
[TestCase(@"""Joe Smith"" email@domain.com")]
[TestCase(@"""Joe\\tSmith"" email@domain.com")]
[TestCase(@"""Joe\""Smith"" email@domain.com")]
[TestCase(@"Test |<gaaf <email@domain.com>")]
[TestCase("MailTo:casesensitve@domain.com")]
[TestCase("mailto:email@domain.com")]
[TestCase("Joe Smith <mailto:email@domain.com>")]
[TestCase("Joe Smith <mailto:email(with comment)@domain.com>")]
[TestCase(@"""With extra < within quotes"" Display Name<email@domain.com>")]
[TestCase("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
public void IsValid(string email)
{
    Assert.IsTrue(EmailAddress.IsValid(email), email);
}

老实说,在产品代码中,我所做的最好的事情就是检查@符号。

我从来没有在一个地方完全验证电子邮件。你知道我怎么判断它是否有效吗?如果发送出去了。如果没有,那就糟了,如果有,生活就好了。这就是我需要知道的。

/使用内部Regex在.Net4.5 >>>中创建“new EmailAddressAttribute();”组件,使用System.ComponentModel.DataAnnotations; //验证邮箱地址......测试和工作。

public bool IsEmail(string email)
{
    if (String.IsNullOrEmpty(email))
    {   return false;  }
    try
    {
        Regex _regex = new Regex("^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])" +
                "+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)" +
                "((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|" +
                "[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\u" +
                "FDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|" +
                "(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|" +
                "[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900" +
                "-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFF" +
                "EF])))\\.?$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
        return _regex.IsMatch(email);
    }
    catch (RegexMatchTimeoutException)
    {
        return false;
    }
}

你也可以用这个:

http://msdn.microsoft.com/en-us/library/01escwtf (v = vs.110) . aspx