【问题标题】:How do I validate an Australian Medicare number?如何验证澳大利亚医疗保险号码?
【发布时间】:2010-08-28 03:23:46
【问题描述】:

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

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

那我该怎么做呢?

(最好用 Javascript 或正则表达式给出答案。)

【问题讨论】:

    标签: javascript validation numbers


    【解决方案1】:

    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. 此医疗保险号码的校验位为 0。

    来源:“健康软件系统中医疗保健标识符的使用 - 软件一致性要求,1.4 版”,NEHTA,2011 年 3 月 5 日

    【讨论】:

    【解决方案2】:

    如果您正在寻找 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. Medicare 卡中的前 9 个数字将对应于实际的 Medicare 编号(用于支票)。
    2. 第 9 位是在GetMedicareChecksum 方法中计算的校验位。
    3. 第 10 位数字标识卡号,因此如果您已获得 3 张卡(因为您丢失了它或其他原因),则编号为 3
    4. 第 11 位数字将标识组内的家庭成员。

    希望有人觉得这很有用。

    【讨论】:

      【解决方案3】:

      这是一个 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/

      【讨论】:

      • return {invalid: true} 应该返回 false。
      • 有一个updoot。
      【解决方案4】:

      添加了 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: "")
      }
      }
      

      【讨论】:

        【解决方案5】:

        添加 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;
        
        }
        

        【讨论】:

          【解决方案6】:

          我的澳大利亚医疗保险号码是 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;
          

          【讨论】:

          • 您可以进一步优化正则表达式以使用正则表达式处理第一个数字检查:^[2-6]\d{3}[ ]?\d{5}[ ]?\d{1}[- ]?\d?$
          【解决方案7】:

          接受的答案,适用于 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;
          };
          

          【讨论】:

          • 此函数不检查第一个数字是否为 2-6。在检查输入是否有值后,我刚刚添加了一个额外的检查,if (!val.match(/^[2-6]\d{3}\s?\d{5}\s?\d{1}$/)) return false;
          【解决方案8】:

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

          你可以使用它

          [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;
              }
          }
          

          【讨论】:

            【解决方案9】:

            添加 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;
            }
            

            【讨论】:

              【解决方案10】:

              另一个使用 cmets 的 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
              }
              

              【讨论】:

                【解决方案11】:

                如果你需要一个测试卡号进行开发,使用这个。这是给 John Doe 的

                测试卡号 > 2428 77813 2/1

                【讨论】:

                  【解决方案12】:

                  扩展 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;}
                  

                  【讨论】:

                    【解决方案13】:

                    这是一个 Python 版本! 请注意,它需要一个完整的 11 位医疗保险号码。 如果您要验证 10 位数的 Medicare 号码而没有个人参考号码,则需要调整 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
                    

                    【讨论】:

                      【解决方案14】:

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

                      在这里查看我的示例: codesandbox.io

                      【讨论】:

                      • 您的代码仅格式化医疗保险号码的显示,而不是实际检查其有效性。
                      猜你喜欢
                      • 2015-06-04
                      • 1970-01-01
                      • 2015-07-13
                      • 2013-03-13
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多