使用RegularExpressionAttribute时,客户端验证无法正常工作。

4

我在使用MVC3RTM时无法实现正则表达式的客户端验证。当我注释掉RegularExpression属性时,所有其他的客户端验证都正常工作,所以我知道它是导致问题的原因。

我有一个简单的模型。(SiteText和SiteErrors只是资源文件)

 public class NewUser {

        [Required]
        [MultiCulturalDisplayName("UserName", typeof(SiteText))]
        public string UserName { get; set; }

        [Required]
        [AllowHtml]
        [RegularExpression(RegExConstants.EmailRegEx, ErrorMessageResourceType = typeof(SiteErrors), ErrorMessageResourceName = "EmailInvalid")]
        [DataType(DataType.EmailAddress)]
        [MultiCulturalDisplayName("EmailAddress", typeof(SiteText))]
        public string Email { get; set; }

        [Required]
        [ValidatePasswordLength]
        [DataType(DataType.Password)]
        [MultiCulturalDisplayName("Password", typeof(SiteText))]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [MultiCulturalDisplayName("PasswordConfirm", typeof(SiteText))]
        [Compare("Password", ErrorMessageResourceType = typeof(SiteErrors), ErrorMessageResourceName = "PasswordCompare")]
        public string ConfirmPassword { get; set; }
    }

这是我存储在常量中的C#转义正则表达式字符串。

^((?>[a-zA-Z\\d!#$%&'*+\\-/=?^_`{|}~]+\\x20*|\"((?=[\\x01-\\x7f])[^\"\\\\]|\\\\[\\x01-\\x7f])*\"\\x20*)*(?<angle><))?((?!\\.)(?>\\.?[a-zA-Z\\d!#$%&'*+\\-/=?^_`{|}~]+)+|\"((?=[\\x01-\\x7f])[^\"\\\\]|\\\\[\\x01-\\x7f])*\")@(((?!-)[a-zA-Z\\d\\-]+(?<!-)\\.)+[a-zA-Z]{2,}|\\[(((?(?<!\\[)\\.)(25[0-5]|2[0-4]\\d|[01]?\\d?\\d)){4}|[a-zA-Z\\d\\-]*[a-zA-Z\\d]:((?=[\\x01-\\x7f])[^\\\\\\[\\]]|\\\\[\\x01-\\x7f])+)\\])(?(angle)>)$

这是未转义版本。

^((?>[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+\x20*|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*"\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+)+|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$

正则表达式太长了是否可能呢?


到底是什么问题?网站有问题吗,还是验证总是失败?如果是这样,请提供一个应该匹配的字符串示例。 - Jens
3个回答

3
除了正则表达式参数之外,看看我的博客文章,了解如何在使用ASP.NET MVC 3和不显眼验证的情况下使电子邮件验证在客户端起作用。
此方法使用内置的jQuery验证电子邮件验证,而不是您自己的正则表达式。但会在服务器端使用您的正则表达式。我不知道jQuery验证使用什么样的正则表达式,所以这可能是好事或坏事。 ASP.NET MVC 3 Email Validation with Unobtrusive jQuery Validation 这非常简单,如果您想更改正则表达式,只需插入自己的正则表达式即可。
这就是其核心。
namespace PageDesigners.Library.ValidationAttributes
{
    public class EmailAttribute : RegularExpressionAttribute, IClientValidatable
    {
        public EmailAttribute()
            : base(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                   @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                   @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")
        {
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var errorMessage = FormatErrorMessage(metadata.GetDisplayName());

            yield return new EmailValidationRule(errorMessage);
        }
    }

    public class EmailValidationRule : ModelClientValidationRule
    {
        public EmailValidationRule(string errorMessage)
        {
            ErrorMessage = errorMessage;
            ValidationType = "email";
        }
    }
}

自您发布代码和今天发布ASP.NET MVC 3以来,一定有些变化。在尝试编译您的代码时,出现了错误,因为您的方法“GetClientValidationRules”无法实现,因为它没有匹配的返回类型“System.Collections.Generic.IEnumerable<System.Web.Mvc.ModelClientValidationRule>”。修复很简单,只需将public IEnumerable GetClientValidationRules更改为public IEnumerable<System.Web.Mvc.ModelClientValidationRule>即可。 - Nick Bork
@Charlino,链接已经失效。 - Hakan Fıstık

2
首先让我们以详细的方式注释一下你的正则表达式:
Regex regexObj = new Regex(
    @"# Match an email address with optional leading words.
    ^                                    # Anchor to start of string
    (                                    # $1: Stuff preceding email address.
      (?>                                # Either...
        [a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]   # A 'word' followed by
        +\x20*                           # zero or more spaces,
      | ""                               # or a double quoted string
        ( (?=[\x01-\x7f])[^""\\]         # consisting of either one regular
        | \\[\x01-\x7f]                  # or one escaped character,
        )*                               # zero or more, followed by
        ""\x20*                          # zero or more spaces.
      )*                                 # Zero or more preceding stuff.
      (?<angle><)                        # $angle: < required before email
    )?                                   # address if there is stuff before.
    (                                    # $2: Email address name portion.
      (?!\.)                             # Must not start with literal dot.
      (?>\.?                             # A dot separates each
        [a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+  # name-word.
      )+                                 # One or more dot-separated name-words.
    | ""                                 # or a double quoted string
      ( (?=[\x01-\x7f])[^""\\]           # consisting of either one regular
      | \\[\x01-\x7f]                    # or one escaped character,
      )*                                 # zero or more.
      ""                                 # Closing quote.
    )                                    # End $2: Email address name portion.
    @                                    # @ separates name and domain portions.
    (                                    # $3: Email domain portion.
      ((?!-)[a-zA-Z\d\-]+(?<!-)\.)+      # One or more dot separated subdomains
      [a-zA-Z]{2,}                       # followed by top level domain,
    | \[                                 # or a IP literal host address
      (                                  # $4: A literal IP address.
        (                                # $5: An IPv4 address
          (?(?<!\[)\.)                   # Dot comes before all but first digit.
          (25[0-5]|2[0-4]\d|[01]?\d?\d)  # ($6:) Each digit is from 0-255.
        ){4}                             # Four dotted-quad numbers required.
      | [a-zA-Z\d\-]*[a-zA-Z\d]:         # Or a word followed by a colon
        (                                # ($6:) followed by
          (?=[\x01-\x7f])[^\\[\]]        # non-escaped ASCII char except '[]'
        |\\[\x01-\x7f]                   # or any escaped non-NULL, ASCII char
        )+                               # One or more of these following colon.
      )\]                                # End $4: The literal IP address.
    )                                    # End $3: Email domain portion.
    (?(angle)>)                          # If there was a <, match closing >.
    $                                    # Anchor to start of string.
    ", 
    RegexOptions.IgnorePatternWhitespace);

请注意,此正则表达式允许在实际电子邮件地址之前出现多个单词。我的测试表明,这个电子邮件匹配子表达式实际上工作得还不错(尽管我对字面IP域名子表达式表示怀有严重的疑虑)。
但在回答您的问题之前,我们需要看看正则表达式在您的代码中实际编译和应用的方式……
顺便说一下,我见过的最准确(并且普通人可以读懂的)电子邮件验证代码是:Cal Henderson的PHP:解析PHP中的电子邮件地址

我删除了过于主观的评论。非常抱歉。我只是想帮忙! - ridgerunner
我感激你的帮助,相信我,这个长长的解释肯定会对某些人有所帮助。虽然有些人可能不喜欢被告知他们应该被枪杀 :-) - Razor

0

试试这个:

[RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}", ErrorMessage = " Invalid Email")]

我可能应该提到,我尝试了一个更简单的正则表达式,它起作用了。谢谢你的解决方案,虽然这个正则表达式不如我所希望的那么全面。 - Razor
1
这个正则表达式包含了常用但已过时和错误的顶级域名表达式:\.[A-Za-z]{2,4},无法匹配超过4个字符的有效域名,例如.museum.travel - ridgerunner
请注意,此正则表达式可能匹配电子邮件地址,但它并不验证其有效性。用于验证电子邮件地址的正则表达式要复杂得多。 - ridgerunner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接