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

Swedish SSN Regular expression reject users under a specific age

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

但如果用户未满 18 岁,我也想拒绝用户注册。我的正则表达式现在看起来像这样:有没有人遇到过年龄范围瑞典 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)");
    }
}

您需要从 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)] 匹配 -|(、空格或 )。我确定您只想匹配连字符或空格。

我在正则表达式中添加了命名捕获并从字符 class 中删除了不必要的符号。另外,请注意 {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)");
    }
}

在这种情况下,我不会使用正则表达式,而是依赖基础 class 库的内置 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 进行比较以确定是否要拒绝它。

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

我建议不要使用自定义 RegEx,而是查看可用的 NuGet 包,它能够解析有效的瑞典个人身份证号码,然后提取可用作输入的信息,例如出生日期、年龄、性别等你的验证。 .GetAge() 方法与您的情况最相关。 免责声明:我是该软件包的合著者之一。

使用 SwedishPersonalIdentityNumberValidateOfAge 的实现可能如下所示:

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.");
    }
}

SwedishPersonalIdentityNumber 支持您描述的模式,包括更多有效模式(例如,您知道 PIN 可以包含 + 吗?)。

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

目前提出的API设计是这样的(针对你的场景):

[SwedishPersonalIdentityNumber(MinimumAge = 18)]
public string PersonalIdentityNumber { get; set; }

如果您希望看到实施,请在问题中分享您的想法。