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


当前回答

我根据维基百科的规则和样本地址创建了一个电子邮件地址验证程序。对于那些不介意多看一点代码的人,这里。说实话,我不知道电子邮件地址规范中有这么多疯狂的规则。我没有完全验证主机名或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;
        }
    }
}

其他回答

Personally, I would say that you should just make sure there is an @ symbol in there, with possibly a . character. There's many regexes you could use of varying correctness, but I think most of these leave out valid email addresses, or let invalid ones through. If people want to put in a fake email address, they will put in a fake one. If you need to verify that the email address is legit, and that the person is in control of that email address, then you will need to send them an email with a special coded link so they can verify that it indeed is a real address.

我最终使用了这个正则表达式,因为它成功地验证了逗号、注释、Unicode字符和IP(v4)域地址。

有效地址为:

“@example。org (评论)test@example。org тест@example。org ტესტი@example。org test@[192.168 . 1章1段]

 public const string REGEX_EMAIL = @"^(((\([\w!#$%&'*+\/=?^_`{|}~-]*\))?[^<>()[\]\\.,;:\s@\""]+(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))(\([\w!#$%&'*+\/=?^_`{|}~-]*\))?@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$";

对@齿轮回答做了一点修改

public static bool IsValidEmail(this string email)
{
  // skip the exception & return early if possible
  if (email.IndexOf("@") <= 0) return false;

  try
  {
    var address = new MailAddress(email);
    return address.Address == email;
  }
  catch
  {
    return false;
  }
}

在“尝试块”发送一个验证电子邮件。 让用户打开电子邮件并单击一个链接,以验证电子邮件是真实的。

在此过程成功完成之前,该电子邮件被认为是无效的。

我是来偷电子邮件的验证码的。然后我发现答案中的代码不必要地扩展了。我相信我用最短的方式写出了最好的解决方案:

public static bool IsEmail(string email)
{
    try
    {
        return new System.Net.Mail.MailAddress(email).Address == email && !email.Trim().EndsWith(".");
    }
    catch
    {
        return false;
    }
}