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.)
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.
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.
When entering Medicare Numbers on the Claim form, please ensure the numbers are correct and there are 11 digits in total with no spaces.
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.
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:
Note: the first digit of the Medicare card number should be in the range 2 to 6.
Medicare card number check digit calculation
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.
Example: For Medicare card number 2123 4567.
Source: "Use of Healthcare Identifiers in Health Software Systems - Software Conformance Requirements, Version 1.4", NEHTA, 3/05/2011
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:
GetMedicareChecksum
method.Hope someone finds this useful.
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/
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: "")
}
}
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.:
5101 20591 8-1
5101 20591 8-2
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With