Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I validate an Australian Medicare number?

I'm developing an online form in which user-entered Medicare numbers will need to be validated.

(My specific problem concerns Australian Medicare numbers, but I'm happy for answers regarding American ones too. This question is about Medicare numbers in general.)

So how should I do it?

(It would be good to have the answer in Javascript or a regex.)

like image 339
Jonathan Avatar asked Aug 28 '10 03:08

Jonathan


People also ask

How do I verify my Medicare number?

If you don't have an account yet, visit MyMedicare.gov to create one. You can sign in to see your Medicare Number or print an official copy of your card. Call 1-800-MEDICARE (1-800-633-4227). TTY users can call 1-877-486-2048.

How many digits is a Medicare number Australia?

This identifier profile defines a Medicare card number in an Australian context. This definition supports sending either the 10 digit Medicare card number or the 11 digit number (includes the individual reference number (IRN)). A Medicare card is provided to individuals who are enrolled in Medicare.

Is Medicare number 11 digits?

When entering Medicare Numbers on the Claim form, please ensure the numbers are correct and there are 11 digits in total with no spaces.

What do the numbers on a Medicare card mean?

individual reference number (IRN) A number that represents the position of a person on a Medicare card. For example, a person who is listed second on a Medicare Card has an IRN of 2. The IRN appears to the left of the patient's name on their Medicare card. This is not a unique identifier.


5 Answers

The regex supplied by Jeffrey Kemp (March 11) would help to validate the allowed characters, but the check algorithm below should be enough to validate that the number conforms to Medicare's rules.

The Medicare card number comprises:

  • Eight digits;
  • A check digit (one digit); and
  • An issue number (one digit).

Note: the first digit of the Medicare card number should be in the range 2 to 6.

Medicare card number check digit calculation

  1. 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))

where digit 1 is the highest place value digit of the Medicare card number and digit 8 is the lowest place value digit of the Medicare card number.

Example: for Medicare card number '2123 45670 1', digit 1 is 2 and digit 8 is 7.

  1. Divide the calculated sum by 10.
  2. The check digit is the remainder.

Example: For Medicare card number 2123 4567.

  1. (2) + (1 * 3) + (2 * 7) + (3 * 9) + (4) + (5 * 3) + (6 * 7) + (7 * 9) = 170
  2. Divide 170 by 10. The remainder is 0.
  3. The check digit for this Medicare number is 0.

Source: "Use of Healthcare Identifiers in Health Software Systems - Software Conformance Requirements, Version 1.4", NEHTA, 3/05/2011

like image 95
brenwickham Avatar answered Oct 14 '22 11:10

brenwickham


If you are looking for a C# version, give this a try:

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

Note: This will return false for null values, you might want to throw an exception.

To clarify:

  1. The first 9 Numbers in the medicare card would correspond to the actual medicare number (used in the check).
  2. The 9th digit is a check digit calculated in the GetMedicareChecksum method.
  3. The 10th digit identifies the number of the card, so if you've been issued 3 cards (because you've lost it or whatever), the number would be 3
  4. The 11th digit would identify the family member inside the group.

Hope someone finds this useful.

like image 20
Daniel Ormeño Avatar answered Oct 14 '22 10:10

Daniel Ormeño


Here's a Typescript or modern Javascript solution:

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

Please refer to http://clearwater.com.au/code/medicare for an explanation.

To test, generate medicare number here: https://precedencehealthcare.com/rmig/

like image 44
Ben Gulapa Avatar answered Oct 14 '22 10:10

Ben Gulapa


Added Swift version

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
}

I use some String extensions as well to simplify some operations.

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: "")
}
}
like image 45
David Rees Avatar answered Oct 14 '22 10:10

David Rees


My Australian Medicare number is 11 numeric digits and includes no letters or other characters.

It is formatted in groups, and the last digit varies according to the member of my family, e.g.:

  • Me: 5101 20591 8-1
  • My wife: 5101 20591 8-2
  • My first child: 5101 20591 8-3

I've seen medicare numbers formatted without the spaces and the dash, but the meaning is the same, so I'd expect to accept 51012059181 as a valid Medicare number as well.

I've also seen context where the last digit is not required or not supposed to be entered; e.g. 5101205918, I guess where they're only interested in the family as a whole.

Therefore, I think this may be appropriate:

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

EDIT

Based on the logic in user2247167's answer, I've used the following PL/SQL function in my Apex application to give a user-friendly warning to the user:

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;
like image 32
Jeffrey Kemp Avatar answered Oct 14 '22 10:10

Jeffrey Kemp