繁体   English   中英

如何验证澳大利亚医疗保险号码?

[英]How do I validate an Australian Medicare number?

我正在开发一个在线表格,其中需要验证用户输入的医疗保险号码。

(我的具体问题涉及澳大利亚医疗保险号码,但我也很高兴得到有关美国医疗保险号码的答案。这个问题是关于一般医疗保险号码的。)

那我应该怎么做呢?

(最好用 Javascript 或正则表达式来回答。)

Jeffrey Kemp(3 月 11 日)提供的正则表达式将有助于验证允许的字符,但下面的检查算法应该足以验证数字是否符合 Medicare 的规则。

Medicare 卡号包括:

  • 八位数字;
  • 一个校验位(一位);
  • 问题编号(一位)。

注意:Medicare 卡号的第一位数字应在 2 到 6 之间。

医保卡号校验位计算

  1. 计算总和:((digit 1) + (digit 2 * 3) + (digit 3 * 7) + (digit 4 * 9) + (digit 5) + (digit 6 * 3) + (digit 7 * 7) +(数字 8 * 9))

其中第 1 位是 Medicare 卡号的最高位值数字,第 8 位是 Medicare 卡号的最低位值位。

示例:对于 Medicare 卡号“2123 45670 1”,数字 1 为 2,数字 8 为 7。

  1. 将计算出的总和除以 10。
  2. 校验位是余数。

示例:对于 Medicare 卡号 2123 4567。

  1. (2) + (1 * 3) + (2 * 7) + (3 * 9) + (4) + (5 * 3) + (6 * 7) + (7 * 9) = 170
  2. 170 除以 10,余数为 0。
  3. 此 Medicare 号码的校验位是 0。

来源:“在健康软件系统中使用医疗保健标识符 - 软件一致性要求,版本 1.4”,NEHTA,3/05/2011

如果您正在寻找 C# 版本,请尝试一下:

using System.Linq;

//...

public bool IsMedicareFormatValid(string medicareNumber)
{
    if (!(medicareNumber?.Length >= 10 && medicareNumber.Length <12) || !medicareNumber.All(char.IsDigit))
        return false;

    var digits = medicareNumber.Select(c => (int) char.GetNumericValue(c)).ToArray();
    return digits[8] == GetMedicareChecksum(digits.Take(8).ToArray());
}

private int GetMedicareChecksum(int[] digits)
{
    return digits.Zip(new[] { 1, 3, 7, 9, 1, 3, 7, 9 }, (m, d) => m*d).Sum() % 10;
}

注意:对于空值,这将返回 false,您可能想要抛出异常。

澄清:

  1. 医疗保险卡中的前 9 个数字将对应于实际医疗保险编号(用于支票)。
  2. 第 9 位是在GetMedicareChecksum方法中计算的校验位。
  3. 第 10 位数字标识卡的编号,因此如果您已获得 3 张卡(因为您丢失或其他原因),则编号为 3
  4. 第 11 位数字将标识组内的家庭成员。

希望有人觉得这很有用。

这是一个 Typescript 或现代 Javascript 解决方案:

  validateMedicare(medicare) {
    let isValid = false;

    if (medicare && medicare.length === 10) {
      const matches = medicare.match(/^(\d{8})(\d)/);

      if (!matches) {
        return { invalid: true };
      }

      const base = matches[1];
      const checkDigit = matches[2];
      const weights = [1, 3, 7, 9, 1, 3, 7, 9];

      let sum = 0;
      for (let i = 0; i < weights.length; i++) {
        sum += parseInt(base[i], 10) * weights[i];
      }

      isValid = sum % 10 === parseInt(checkDigit, 10);
    }

    return isValid;
  }

请参阅http://clearwater.com.au/code/medicare以获得解释。

要进行测试,请在此处生成医疗保险编号: https : //precedencehealthcare.com/rmig/

添加了 Swift 版本

class func isMedicareValid(input : String, validateWithIrn : Bool) -> Bool {
    let multipliers = [1, 3, 7, 9, 1, 3, 7, 9]

    let pattern = "^(\\d{8})(\\d)"
    let medicareNumber = input.removeWhitespace()
    let length = validateWithIrn ? 11 : 10

    if medicareNumber.characters.count != length {return false}

    let expression = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.CaseInsensitive)

    let matches = expression.matchesInString(medicareNumber, options: NSMatchingOptions.ReportProgress, range: NSMakeRange(0, length))

    if (matches.count > 0 && matches[0].numberOfRanges > 2) {
        let base = medicareNumber.substringWithRange(medicareNumber.startIndex...medicareNumber.startIndex.advancedBy(matches[0].rangeAtIndex(1).length))
        let checkDigitStartIndex = medicareNumber.startIndex.advancedBy(matches[0].rangeAtIndex(2).location )
        let checkDigitEndIndex = checkDigitStartIndex.advancedBy(matches[0].rangeAtIndex(2).length)
        let checkDigit = medicareNumber.substringWithRange(checkDigitStartIndex..<checkDigitEndIndex)
        var total = 0

        for i in 0..<multipliers.count {
            total += Int(base.charAtIndex(i))! * multipliers[i]
        }

         return (total % 10) == Int(checkDigit)
    }
    return false
}

我也使用一些字符串扩展来简化一些操作。

extension String {

func charAtIndex (index: Int) -> String{
    var character = ""
    if (index < self.characters.count){
        let locationStart = self.startIndex.advancedBy(index)
        let locationEnd = self.startIndex.advancedBy(index + 1 )
        character = self.substringWithRange(locationStart..<locationEnd)
    }
    return character
}

func replace(string:String, replacement:String) -> String {
    return self.stringByReplacingOccurrencesOfString(string, withString: replacement, options: NSStringCompareOptions.LiteralSearch, range: nil)
}

func removeWhitespace() -> String {
    return self.replace(" ", replacement: "")
}
}

添加了 Java 版本

public static boolean isMedicareValid(String input, boolean validateWithIRN){
    int[] multipliers = new int[]{1, 3, 7, 9, 1, 3, 7, 9};
    String pattern = "^(\\d{8})(\\d)";
    String medicareNumber = input.replace(" " , "");
    int length = validateWithIRN ? 11 : 10;

    if (medicareNumber.length() != length) {return false;}

    Pattern medicatePattern = Pattern.compile(pattern);
    Matcher matcher = medicatePattern.matcher(medicareNumber);

    if (matcher.find()){

        String base = matcher.group(1);
        String checkDigit = matcher.group(2);

        int total = 0;
        for (int i = 0; i < multipliers.length; i++){
            total += base.charAt(i) * multipliers[i];
        }

        return ((total % 10) == Integer.parseInt(checkDigit));
    }

    return false;

}

我的澳大利亚医疗保险号码是 11 位数字,不包含字母或其他字符。

它是按组格式化的,最后一位数字因我的家庭成员而异,例如:

  • 我: 5101 20591 8-1
  • 老婆: 5101 20591 8-2
  • 我的第一个孩子: 5101 20591 8-3

我见过格式不带空格和破折号的医疗保险号码,但含义是一样的,所以我希望也接受51012059181作为有效的医疗保险号码。

我还看到了不需要或不应该输入最后一位数字的上下文; 例如5101205918 ,我猜他们只对整个家庭感兴趣。

因此,我认为这可能是合适的:

^\d{4}[ ]?\d{5}[ ]?\d{1}[- ]?\d?$

编辑

根据 user2247167 的回答中的逻辑,我在我的 Apex 应用程序中使用了以下 PL/SQL 函数来向用户发出用户友好的警告:

FUNCTION validate_medicare_no (i_medicare_no IN VARCHAR2)
  RETURN VARCHAR2 IS
  v_digit1 CHAR(1);
  v_digit2 CHAR(1);
  v_digit3 CHAR(1);
  v_digit4 CHAR(1);
  v_digit5 CHAR(1);
  v_digit6 CHAR(1);
  v_digit7 CHAR(1);
  v_digit8 CHAR(1);
  v_check  CHAR(1);
  v_result NUMBER;
BEGIN
  IF NOT REGEXP_LIKE(i_medicare_no, '^\d{10}\d?{2}$') THEN
    RETURN 'Must be 10-12 digits, no spaces or other characters';
  ELSE
    v_digit1 := SUBSTR(i_medicare_no, 1, 1);
    IF v_digit1 NOT IN ('2','3','4','5','6') THEN
      RETURN 'Not a valid Medicare number - please check and re-enter';
    ELSE
      v_digit2 := SUBSTR(i_medicare_no, 2, 1);
      v_digit3 := SUBSTR(i_medicare_no, 3, 1);
      v_digit4 := SUBSTR(i_medicare_no, 4, 1);
      v_digit5 := SUBSTR(i_medicare_no, 5, 1);
      v_digit6 := SUBSTR(i_medicare_no, 6, 1);
      v_digit7 := SUBSTR(i_medicare_no, 7, 1);
      v_digit8 := SUBSTR(i_medicare_no, 8, 1);
      v_check  := SUBSTR(i_medicare_no, 9, 1);
      v_result := mod(   to_number(v_digit1)
                      + (to_number(v_digit2) * 3)
                      + (to_number(v_digit3) * 7)
                      + (to_number(v_digit4) * 9)
                      +  to_number(v_digit5)
                      + (to_number(v_digit6) * 3)
                      + (to_number(v_digit7) * 7)
                      + (to_number(v_digit8) * 9)
                     ,10);
      IF TO_NUMBER(v_check) != v_result THEN
        RETURN 'Not a valid Medicare number - please check and re-enter';
      END IF;
    END IF;
  END IF;
  -- no error
  RETURN NULL;
END validate_medicare_no;

接受的答案,适用于 JavaScript:

var validator = function (input, validateWithIrn) {
    if (!input) {
        return false;
    }

    var medicareNumber;
    var pattern;
    var length;
    var matches;
    var base;
    var checkDigit;
    var total;
    var multipliers;
    var isValid;

    pattern = /^(\d{8})(\d)/;
    medicareNumber = input.toString().replace(/ /g, '');
    length = validateWithIrn ? 11 : 10;

    if (medicareNumber.length === length) {
        matches = pattern.exec(medicareNumber);
        if (matches) {
            base = matches[1];
            checkDigit = matches[2];
            total = 0;
            multipliers = [1, 3, 7, 9, 1, 3, 7, 9];

            for (var i = 0; i < multipliers.length; i++) {
                total += base[i] * multipliers[i];
            }

            isValid = (total % 10) === Number(checkDigit);
        } else {
            isValid = false;
        }
    } else {
        isValid = false;
    }

    return isValid;
};

我找到了关于这个主题的论坛讨论:

http://regexadvice.com/forums/thread/57337.aspx

我打算尝试一下'澳洲苏珊'想出的:

^\d{9}B[ADGHJKLNPQRTWY1-9,]?$

您可以创建验证属性来验证医疗保险号码

您可以通过以下方式使用它

[AustralianMedicareNumberOnly]
public string MedicareNo { get; set; }

代码

public class AustralianMedicareNumberOnlyAttribute : ValidationAttribute
{
    private string exampleNumber = "Example: 2234 56789 1-2";

    public AustralianMedicareNumberOnlyAttribute()
    {
        ErrorMessage = string.Concat("{0} is not in correct format, ", exampleNumber);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            string objectValueString;
            int[] checksumDigits = new int[] { 1, 3, 7, 9, 1, 3, 7, 9 };
            int checksumDigit;
            int checksumtotal = 0;
            int checksumDigitCalculated;

            //convert incomming object value to string
            objectValueString = Convert.ToString(value).Trim();

            // check medicare number format should be 1234 56789 1-2
            if (!Regex.IsMatch(objectValueString, @"^[2-6]\d{3}\s\d{5}\s\d{1}-\d{1}$"))
            {
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
            }
            else
            { 
                //Check checksum value
                //--------------------

                // replace two spaces and one dash
                objectValueString = objectValueString.Replace(" ", "").Replace("-", "");

                // Calculate the sum of: ((digit 1) + (digit 2 * 3) + (digit 3 * 7) + (digit 4 * 9) + (digit 5) + (digit 6 * 3) + (digit 7 * 7) + (digit 8 * 9))
                for (int i = 0; i < checksumDigits.Length; i++)
                {
                    int digit = Convert.ToInt32(objectValueString.Substring(i, 1));

                    checksumtotal += digit * checksumDigits[i];
                }

                //find out checksum digit
                checksumDigit = Convert.ToInt32(objectValueString.Substring(8, 1));
                checksumDigitCalculated = checksumtotal % 10;

                // check calculated checksum with medicare checksum digit
                if (checksumDigit!= checksumDigitCalculated)
                {
                    return new ValidationResult("The Medicare Number is not Valid.");
                }

            }

        }

        return ValidationResult.Success;
    }
}

添加了 Dart 版本:

bool isMedicareValid(String input, {bool validateWithIrn = true}) {
  final medicareNumber = input.replaceAll(" ", "");
  final length = validateWithIrn ? 11 : 10;

  if (medicareNumber.length != length) {
    return false;
  }

  final multipliers = [1, 3, 7, 9, 1, 3, 7, 9];
  final regexp = RegExp("^(\\d{8})(\\d)", caseSensitive: false);

  final matches = regexp.allMatches(medicareNumber).toList();

  if (matches.length > 0 && matches[0].groupCount >= 2) {
    final base = matches[0].group(1);
    final checkDigit = matches[0].group(2);
    var total = Iterable.generate(multipliers.length)
        .fold(0, (current, index) => current += (int.tryParse(base[index]) * multipliers[index]));

    return (total % 10) == int.parse(checkDigit);
  }
  return false;
}

另一个带有注释的 Swift 实现:

func validateMedicareNumber(input: String) -> Bool {
    let weights = [1, 3, 7, 9, 1, 3, 7, 9]

    // Remove all whitespace
    var trimmed = input.trimmingCharacters(in: .whitespacesAndNewlines)
        .components(separatedBy: .whitespaces)
        .joined()

    // The medicare card number has 8 digits identifier + 1 digit checksum + 1 digit issue number.
    // Either 9 or 10 numbers will be valid
    guard trimmed.count == 9 || trimmed.count == 10 else {
        return false
    }

    // Drop the issue number if it was added
    if trimmed.count == 10 {
        trimmed = String(trimmed.dropLast())
    }

    // The last digit is a checksum
    guard let lastElement = trimmed.last,
        let checkSum = Int(String(lastElement)) else {
        return false
    }

    // Remove the checksum from our input
    trimmed = String(trimmed.dropLast())

    // Multiply the numbers by weights
    let weightedNumbers: [Int] = trimmed.enumerated().map { index, element in
        guard let number = Int(String(element)) else {
            // -1 will throw the calculations out of the window which
            // will guarantee invalid checksum
            return -1
        }

        return number * weights[index]
    }

    // Validate the weighted numbers against the checksum
    return weightedNumbers.reduce(0, +) % 10 == checkSum
}

如果您需要用于开发的测试卡号,请使用此卡号。 这是给约翰·多伊的

测试卡号 > 2428 77813 2/1

扩展Daniel Ormeño 的答案,对于 asp.net,您可以将支票放入一个属性中并在模型中装饰该属性

public class MedicareValidation : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        string medicareNumber = value.ToString();

        if (!(medicareNumber?.Length >= 10 && medicareNumber.Length < 12) || !medicareNumber.All(char.IsDigit))
            return false;

        var digits = medicareNumber.Select(c => (int)char.GetNumericValue(c)).ToArray();
        return digits[8] == GetMedicareChecksum(digits.Take(8).ToArray());
    }

    private int GetMedicareChecksum(int[] digits)
    {
        return digits.Zip(new[] { 1, 3, 7, 9, 1, 3, 7, 9 }, (m, d) => m * d).Sum() % 10;
    }
}

然后在模型中

[DisplayName("Medicare Number")]  
[MedicareValidation] 
public string MedicareNumber {get; set;}

这是一个 Python 版本! 请注意,它需要一个完整的 11 位医疗保险号码。 如果您要验证 10 位医疗保险号码而没有个人参考号码,则需要调整re.match行中的正则表达式。

def validate_medicare_number(medicare_number: str) -> bool:
    """Given a string containing a medicare number, return True if valid,
    False if invalid.

    >>> validate_medicare_number("2428 77813 2/1")
    True
    >>> validate_medicare_number("7428 77818 2/1")
    False
    >>> validate_medicare_number("2428 77815 2/1")
    False
    """

    # See here for checksum algorithm:
    # https://stackoverflow.com/a/15823818
    # https://clearwater.com.au/code/medicare

    # Remove whitespace
    medicare_number = re.sub(r"[^\d]+", "", medicare_number)
    if re.match(r"^[2-6]\d{10}$", medicare_number):

        medicare_digits = list(map(int, medicare_number))
        checksum_weights = (1, 3, 7, 9) * 2
        digit_weight_pairs = zip(medicare_digits, checksum_weights)
        checksum = sum([digit * weight for digit, weight in digit_weight_pairs]) % 10

        return checksum == medicare_digits[8]
    else:
        return False

微软 SQL Server 2017

假设输入的医疗保险号是干净的。 验证10 位医疗保险号码。 不包括参考编号。

if object_id('dbo.validate_medicare') is not null 
    drop function dbo.validate_medicare;
go 

create function dbo.validate_medicare(@medicareNumber varchar(max)) 
returns int 
as 
begin 

    if len(@medicareNumber) <> 10
        return 0;

    if isnumeric(@medicareNumber) = 0
        return 0;

    declare @count as int = 0;
    declare @firstDigit as int = cast(substring(@medicareNumber, 1, 1) as int);

    if @firstDigit not between 2 and 6
        return 0;

    declare @actualCheckDigit as int = cast(substring(@medicareNumber, 9, 1) as int);
    declare @computedCheckDigit as int;
    declare @weight as int = 1;
    declare @tempStuff table (
        digit int,
        weight int
    );
    declare @isValid as int;


    while @count < len(substring(@medicareNumber, 1, 8))
    begin 
        declare @selected_digit as int = substring(@medicareNumber, @count+1, 1);

        if @weight > 9
            set @weight = 1;

        insert into @tempStuff(digit, weight) values (@selected_digit, @weight);
        set @weight = @weight + 2;

        if @weight = 5
            set @weight = @weight + 2;

        set @count = @count + 1;
    end;

    -- Set the computed Check digit 
    select @computedCheckDigit = (sum(digit * weight)) % 10 from @tempStuff;

    -- Check if computed check digit equals the actual check digit
    set @isValid = case 
                        when @computedCheckDigit = @actualCheckDigit
                            then 1 
                        else 0 
                   end;

    return @isValid;
end;
go

例子

declare @medicareNumber as varchar(11) = '2123456701';
select dbo.validate_medicare(@medicareNumber) as IsValid;

您可以使用简单的正则表达式验证: .replace(/\\W/gi, "") .replace(/(.{4})(.{5})/g, "$1 $2 ");

在此处查看我的示例: codeandbox.io

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM