瑞典SSN正则表达式拒绝特定年龄的用户

时间:2015-09-17 07:32:18

标签: c# .net regex asp.net-mvc regular-language

我的正则表达式有问题。我已经能够确定正确的瑞典社会安全号码以符合这些标准。

  • YYMMDDNNNN
  • YYMMDD-NNNN
  • YYYYMMDDNNNN
  • 年月日 - NNNN

但如果用户未满18岁,我还想拒绝用户注册。我的reqular表达目前看起来像这样:有没有人遇到与年龄范围瑞典SSN相同的问题?

  private const string RegExForValidation =
        @"^(\d{6}|\d{8})[-|(\s)]{0,1}\d{4}$";

更新

 private const string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
        string date = Regex.Match("19970918-1234", RegExForValidation).Groups["date"].Value;
        DateTime dt;

 [Required(ErrorMessage = "Du måste ange personnummer")]
        [RegularExpression(RegExForValidation, ErrorMessage = "Personnummer anges med 10 siffror (yymmddnnnn)")]
        public string PersonalIdentityNumber { get; set; }

第二次更新

 public class ValidateOfAge : ValidationAttribute
{
    public bool IsOfAge(DateTime birthdate)
    {
        DateTime today = DateTime.Today;
        int age = today.Year - 18;
        if (birthdate.AddYears(birthdate.Year) < today.AddYears(-age))
            return false;
        else
            return true;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
        string date = Regex.Match((string)value, RegExForValidation).Groups["date"].Value;
        DateTime dt;
        if (DateTime.TryParseExact(date, new[] { "yyMMdd", "yyyyMMdd" }, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
            if (IsOfAge(dt))
                return ValidationResult.Success;
        return new ValidationResult("Personnummer anges med 10 siffror (yymmddnnnn)");
    }
}

3 个答案:

答案 0 :(得分:3)

这是我不会使用正则表达式的情况,而是依赖于基类库的内置DateTime解析功能:

public DateTime GetBirthDate(string ssn)
{
    var strippedOfSerial =
        ssn.Substring(0, ssn.Length - 4).TrimEnd('-');
    return DateTime.ParseExact(
        strippedOfSerial,
        new[] { "yyMMdd", "yyyyMMdd" },
        new CultureInfo("se-SE"),
        DateTimeStyles.None);
}

现在,您可以查看返回的DateTime值,并将其与DateTime.Now进行比较,以确定是否要拒绝它。

在我看来,这比依赖正则表达式更具可读性,并且可能更安全,更灵活。如您所知,您可以例如使用其他文化等来调整解析策略。

答案 1 :(得分:1)

您需要从SSN获取生日,解析为DateTime,然后与今天的日期进行比较。

以下是检查某人是否年龄的方法:

public bool IsOfAge(DateTime birthdate)
{
    DateTime today = DateTime.Today;       // Calculating age...
    int age = today.Year - birthdate.Year;
    if (birthdate > today.AddYears(-age)) 
        age--;
    return age < 18 ? false : true;   // If the age is 18+ > true, else false.
}

以下是您可以使用的方法:

string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
string date = Regex.Match("19970918-1234", RegExForValidation).Groups["date"].Value;
DateTime dt;
if (DateTime.TryParseExact(date, new[] { "yyMMdd", "yyyyMMdd" }, new CultureInfo("sv-SE"), DateTimeStyles.None, out dt))
   Console.WriteLine(IsOfAge(dt));

请注意,[-|(\s)]-|(,空格或)匹配。我相信你只想匹配一个连字符或空格。

我在正则表达式中添加了一个命名捕获,并从字符类中删除了不必要的符号。另请注意,{0,1}?相同。

<强>更新

要使其在MVC应用程序中运行,您需要实现自定义验证器:

[Required(ErrorMessage = "Du måste ange personnummer")]
[ValidateOfAge]  // <---------------------------- HERE
public string PersonalIdentityNumber { get; set; }

并按如下方式实施:

public class ValidateOfAge: ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {                 
        string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
        string date = Regex.Match((string)value, RegExForValidation).Groups["date"].Value;
        DateTime dt;
        if (DateTime.TryParseExact(date, new[] { "yyMMdd", "yyyyMMdd" }, new CultureInfo("sv-SE"), DateTimeStyles.None, out dt))
            if (IsOfAge(dt))
                return ValidationResult.Success;
        return new ValidationResult("Personnummer anges med 10 siffror (yymmddnnnn)");
    }
}

答案 2 :(得分:0)

建议不要查看自定义的RegEx,而是查看可用的NuGet程序包,该程序包可以解析有效的瑞典个人身份号码,然后提取诸如DateOfBirth,Age,Gender等信息,这些信息可以用作您的输入验证。方法.GetAge()与您的情况最相关。 免责声明:我是该软件包的合著者之一。

使用ValidateOfAge的{​​{1}}的实现如下所示:

SwedishPersonalIdentityNumber

public class ValidateOfAge : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (SwedishPersonalIdentityNumber.TryParse((string)value, out var personalIdentityNumber)) { if(personalIdentityNumber.GetAge() >= 18) { return ValidationResult.Success; } else { return new ValidationResult("Du måste vara minst 18 år gammal."); } } return new ValidationResult("Ogiltigt personnummer."); } } 支持您描述的模式,包括更多有效的模式(例如,您是否知道PIN可以包含+吗?)。

第二个包含一个验证属性,用于验证模型中的PIN。 如果验证年龄的用例足够普遍,我们可以将其实现到该验证属性中。我created an issue来了解兴趣和设计。

目前建议的API设计如下(针对您的情况):

SwedishPersonalIdentityNumber

如果您希望实现此目标,请分享您对该问题的想法。