Как проверить номер Австралийского Medicare?

Я разрабатываю онлайн-форму, в которой должны быть подтверждены введенные пользователем номера Medicare.

(Моя конкретная проблема касается номеров австралийских медиков, но я рад за ответы и на американские. Этот вопрос касается номеров Medicare в целом.)

Итак, как мне это сделать?

(Было бы хорошо иметь ответ в Javascript или регулярном выражении.)

Ответ 1

Регулярное выражение, предоставленное Джеффри Кемпом (11 марта), поможет проверить допустимые символы, но алгоритм проверки ниже должен быть достаточным, чтобы подтвердить, что число соответствует правилам Medicare.

Номер карты Medicare включает в себя:

  • Восемь цифр;
  • Контрольная цифра (одна цифра); и
  • Номер проблемы (одна цифра).

Примечание: первая цифра номера карты Medicare должна быть в диапазоне от 2 до 6.

Расчет количества проверочных карточек Medicare

  • Рассчитать сумму: ((цифра 1) + (цифра 2 * 3) + (цифра 3 * 7) + (цифра 4 * 9) + (цифра 5) + (цифра 6 * 3) + (цифра 7 * 7) + (цифра 8 * 9))

где цифра 1 - это наивысшая цифра значения места в номере карточки Medicare, а цифра 8 - это наименьшая цифра стоимости номера карты Medicare.

Пример: для номера карты Medicare '2123 45670 1', цифра 1 - 2, а цифра 8 - 7.

  • Разделите вычисленную сумму на 10.
  • Контрольная цифра - это остаток.

Пример: Номер карты Medicare № 2123 4567.

  • (2) + (1 * 3) + (2 * 7) + (3 * 9) + (4) + (5 * 3) + (6 * 7) + (7 * 9) = 170
  • Разделите 170 на 10. Остаток равен 0.
  • Контрольная цифра для этого номера Medicare равна 0.

Источник: "Использование идентификаторов здравоохранения в программных системах здравоохранения - Требования к совместимости программного обеспечения, версия 1.4", NEHTA, 3/05/2011

Ответ 2

Если вы ищете версию на С#, попробуйте:

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 для нулевых значений, вы можете захотеть выбросить исключение.

Чтобы уточнить:

  • Первые 9 номеров на карточке медицинского страхования соответствуют фактическому номеру медицинской помощи (используется в чеке).
  • 9-я цифра - контрольная цифра, вычисленная по методу GetMedicareChecksum.
  • 10-я цифра определяет номер карты, поэтому, если вы получили 3 карты (потому что вы ее потеряли или что-то еще), число будет 3
  • 11-я цифра идентифицирует член семьи внутри группы.

Надеюсь, что кто-то найдет это полезным.

Ответ 3

Добавлена ​​версия 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;

}

Ответ 4

Мой австралийский номер Medicare - 11 числовых цифр и не содержит букв или других символов.

Он отформатирован в группах, а последняя цифра изменяется в зависимости от члена моей семьи, например:

  • Me: 5101 20591 8-1
  • Моя жена: 5101 20591 8-2
  • Мой первый ребенок: 5101 20591 8-3

Я видел номера медикаментов, отформатированные без пробелов и тире, но смысл один и тот же, поэтому я ожидал бы принять 51012059181 как действительный номер Medicare.

Я также видел контекст, где последняя цифра не требуется или не должна быть введена; например 5101205918, я думаю, где они интересуются только семьей в целом.

Поэтому я думаю, что это может быть уместно:

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

ИЗМЕНИТЬ

В ответ на логику в user2247167 я использовал следующую функцию PL/SQL в своем приложении Apex, чтобы дать пользователю удобное для пользователя предупреждение:

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;

Ответ 5

Принятый ответ, адаптированный к 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;
};

Ответ 6

Добавлена ​​версия 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: "")
}
}

Ответ 7

Я нашел дискуссию на форуме по теме:

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

Я собираюсь попробовать, что "Aussie Susan" придумал:

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

Ответ 8

Вы можете создать атрибут проверки для проверки номера Medicare

Вы можете использовать его

[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

Вот 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 для объяснения.

Чтобы проверить, сгенерируйте номер Medicare здесь: https://precedencehealthcare.com/rmig/

Ответ 10

Вы можете использовать простую проверку регулярных выражений:.replace(/\ W/gi, "").replace(/(. {4}) (. {5})/g, "$ 1 $ 2");

проверьте мой пример здесь: codesandbox.io