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

本文关键字:用户 SSN 正则表达式 拒绝 瑞典 | 更新日期: 2023-09-27 18:13:10

我的正则表达式有问题。我已经使验证正确的瑞典社会安全号码以匹配这些标准成为可能。

  • YYMMDDNNNN
  • YYMMDD-NNNN
  • YYYYMMDDNNNN
  • YYYYMMDD-NNNN

但我也想拒绝用户注册,如果用户是18岁以下。我的正则表达式现在看起来是这样的:是否有人在瑞典社会安全号的年龄范围中遇到了同样的问题?

  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 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进行比较,以确定是否要拒绝它。

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

您需要从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)");
    }
}

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

使用SwedishPersonalIdentityNumber实现ValidateOfAge可能看起来像:

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可以包含+吗?)

  • 你可以在这里找到源代码:
    • https://github.com/ActiveLogin/ActiveLogin.Identity
  • NuGet上的包在这里:
    • https://www.nuget.org/packages/ActiveLogin.Identity.Swedish/
    • https://www.nuget.org/packages/ActiveLogin.Identity.Swedish.AspNetCore/

第二个包含一个验证属性,用于验证模型中的PIN。如果验证年龄的用例足够常见,我们可以将其实现到验证属性中。我创造了一个问题来找出兴趣和设计。

目前建议的API设计是这样的(针对您的场景):
[SwedishPersonalIdentityNumber(MinimumAge = 18)]
public string PersonalIdentityNumber { get; set; }

如果这是你想看到的,请分享你的想法。