Як визначити тип кредитної картки на основі номера?


516

Я намагаюся розібратися, як визначити тип кредитної картки виходячи виключно з її кількості. Хтось знає про остаточний, надійний спосіб знайти це?


3
Використання регулярного виразу. Перегляньте це посилання для отримання додаткової інформації.
сенфо

3
Детальна інформація у Вікіпедії: en.wikipedia.org/wiki/Credit_card_numbers
Sten Vesterli

1
У Вікіпедії є хороша підсумкова таблиця за адресою en.wikipedia.org/wiki/Credit_card_numbers . Це перша-шість цифр, яка повідомляє тип та емітента картки.
Олексій

3
Я б не використовував регулярний вираз, крім того, щоб витягнути першу числову групу, як правило, ви можете сказати лише з перших чотирьох чисел (у США). Також перед тим, як турбуватись про сплату за плату, запустіть контрольну суму Mod 10 на номер картки, щоб переконатися, що вона може бути законною. Алгоритм Луна
Ден Блер

3
також хтось може прокоментувати, чи ці алгоритми хороші "на весь час" - чи періодично змінюються, як, наприклад, алгоритм "обчислення, якщо номер телефону знаходиться в Каліфорнії"
Simon_Weaver

Відповіді:


771

Номер кредитної / дебетової картки називається ПАН або Основним номером рахунку . Перші шість цифр ПАН взяті з IIN або ідентифікаційного номера емітента , що належить банку-емітенту (IIN раніше були відомі як BIN - Ідентифікаційні номери банків - тому ви можете бачити посилання на цю термінологію в деяких документах). Ці шість цифр підпадають під міжнародний стандарт ISO / IEC 7812 , і їх можна використовувати для визначення типу картки за номером.

На жаль, фактична база даних ISO / IEC 7812 не є загальнодоступною, проте є неофіційні списки, комерційні та безкоштовні, в тому числі у Вікіпедії .

У будь-якому випадку для виявлення типу з числа ви можете використовувати регулярний вираз, як наведений нижче: Запис на оригінальні вирази

Visa: ^4[0-9]{6,}$ Номери карт Visa починаються з 4.

MasterCard: ^5[1-5][0-9]{5,}|222[1-9][0-9]{3,}|22[3-9][0-9]{4,}|2[3-6][0-9]{5,}|27[01][0-9]{4,}|2720[0-9]{3,}$ до 2016 року номери MasterCard починаються з цифр 51 до 55, але це виявить лише кредитні картки MasterCard ; Є й інші картки, видані за допомогою системи MasterCard, які не входять до цього діапазону IIN. У 2016 році вони додадуть цифри в діапазоні (222100-272099).

American Express: ^3[47][0-9]{5,}$ номери картки American Express починаються з 34 або 37.

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ Номери карт Diners Club починаються з 300 до 305, 36 або 38. Є картки Diners Club, які починаються з 5 і мають 16 цифр. Це спільне підприємство між Diners Club та MasterCard, і їх слід обробляти як MasterCard.

Дізнайтеся: ^6(?:011|5[0-9]{2})[0-9]{3,}$ номери карток починаються з 6011 або 65.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ Карти JCB починаються з 2131, 1800 або 35.

На жаль, існує декілька типів карток, оброблених системою MasterCard, які не перебувають у діапазоні IIN MasterCard (числа починаються з 51 ... 55); Найважливіший випадок - це карти Maestro, багато з яких були випущені з діапазонів IIN інших банків, і тому вони розташовані по всьому простору номерів. Як результат, можливо, найкраще припустити, що будь-яка карта, яка не є іншим типом, який ви приймаєте, має бути MasterCard .

Важливо : номери карток різняться за довжиною; наприклад, у минулому Visa випускала картки з 13-значними PAN та картками з 16-значним PAN. Наразі документація Visa вказує на те, що вона може видавати або може видавати номери з 12 до 19 цифрами. Тому вам не слід перевіряти довжину номера картки, крім того, щоб перевірити, чи має вона принаймні 7 цифр (для повного IIN плюс одна контрольна цифра, яка повинна відповідати значенню, передбаченому алгоритмом Луна ).

Ще один натяк: перед тим, як обробити власника картки PAN, зніміть із вводу будь-які пробіли та розділові знаки . Чому? Оскільки, як правило, набагато простіше вводити цифри групами, подібно до того, як вони відображаються на передній частині фактичної кредитної картки, тобто

4444 4444 4444 4444

набагато простіше правильно ввести, ніж

4444444444444444

Немає користі від покарання користувача, оскільки вони ввели символів, яких ви тут не очікуєте.

Це також означає, що у ваших полях для введення є принаймні 24 символи, інакше у користувачів, які вводять пробіли, не вистачить місця. Я рекомендую зробити поле достатньо широким для відображення 32 символів і дозволити до 64; що дає багато місця для розширення.

Ось зображення, яке дає трохи більше розуміння:

ОНОВЛЕННЯ (2014): метод контрольної суми більше не є правильним способом перевірки справжності картки, як зазначено в коментарях до цієї відповіді.

ОНОВЛЕННЯ (2016): Mastercard має впроваджувати нові діапазони BIN, починаючи з Ach Payment .

Підтвердження кредитної картки


7
чудовий приклад. у вас є регулярний вираз для карт maestro?
Манікандан

4
Ні-ні-ні. Ви не можете покладатися на довжину номерів карт; вони можуть змінитися в будь-який час. Єдина частина номера картки, на яку можна покластися, - це IIN (який раніше називався BIN) і який є префіксом номера. Крім того, ви не можете виявити картки Mastercard таким чином, як ви пропонуєте; що підбере лише підмножину карт, які обробляються за допомогою системи Mastercard (головна проблема - карти Maestro, які мають різні префікси IIN).
аластер

2
@alastair Ви читали вирази, перш ніж коментувати? Вони були написані спеціально для використання IIN, тому я не розумію, що ви намагаєтесь сказати. Крім того, IIN можна використовувати для ідентифікації емітента картки, але не підтверджує. 5412, наприклад, не являє собою повну MasterCard, але ваша пропозиція означатиме, що це є. Я не знайшов жодних доказів того, що MasterCards - це нічого, крім 16 цифр. Будь ласка, не соромтеся надати джерело вашої претензії. Однак ви неправомірно згадуєте, що для карт Maestro потрібно зробити оновлення.
сенфо

3
@senfo Ви маєте рацію, 5412 не буде повним номером Mastercard. IIN має шість цифр, тому повний номер картки повинен бути 7 цифр (мінімум) і повинен пройти перевірку Луна. Не потрібно «доказувати», що номери Mastercard мають що-небудь, крім 16 цифр; справа в тому, що, незалежно від ситуації сьогодні, в майбутньому вони можуть видавати картки з 17 або 18 цифрами, або, з цього приводу, деякі з 15. Покладатися на їх 16 цифр не потрібно і створює ризик довгострокового обслуговування.
аластер

3
Мені дуже важко повірити, що деякі дійсні картки не матимуть правильної контрольної цифри згідно алгоритму Люна. Він використовувався абсолютно скрізь, щоб перевірити номери карток на предмет простих друкарських помилок і німих спроб шахрайства. Натомість я помітив, що деякі досить розумні люди просто не розуміють алгоритм, і вони просто неправильно обчислюють його.
Rennex

74

У JavaScript:

function detectCardType(number) {
    var re = {
        electron: /^(4026|417500|4405|4508|4844|4913|4917)\d+$/,
        maestro: /^(5018|5020|5038|5612|5893|6304|6759|6761|6762|6763|0604|6390)\d+$/,
        dankort: /^(5019)\d+$/,
        interpayment: /^(636)\d+$/,
        unionpay: /^(62|88)\d+$/,
        visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
        mastercard: /^5[1-5][0-9]{14}$/,
        amex: /^3[47][0-9]{13}$/,
        diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
        discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
        jcb: /^(?:2131|1800|35\d{3})\d{11}$/
    }

    for(var key in re) {
        if(re[key].test(number)) {
            return key
        }
    }
}

Тест одиниці:

describe('CreditCard', function() {
    describe('#detectCardType', function() {

        var cards = {
            '8800000000000000': 'UNIONPAY',

            '4026000000000000': 'ELECTRON',
            '4175000000000000': 'ELECTRON',
            '4405000000000000': 'ELECTRON',
            '4508000000000000': 'ELECTRON',
            '4844000000000000': 'ELECTRON',
            '4913000000000000': 'ELECTRON',
            '4917000000000000': 'ELECTRON',

            '5019000000000000': 'DANKORT',

            '5018000000000000': 'MAESTRO',
            '5020000000000000': 'MAESTRO',
            '5038000000000000': 'MAESTRO',
            '5612000000000000': 'MAESTRO',
            '5893000000000000': 'MAESTRO',
            '6304000000000000': 'MAESTRO',
            '6759000000000000': 'MAESTRO',
            '6761000000000000': 'MAESTRO',
            '6762000000000000': 'MAESTRO',
            '6763000000000000': 'MAESTRO',
            '0604000000000000': 'MAESTRO',
            '6390000000000000': 'MAESTRO',

            '3528000000000000': 'JCB',
            '3589000000000000': 'JCB',
            '3529000000000000': 'JCB',

            '6360000000000000': 'INTERPAYMENT',

            '4916338506082832': 'VISA',
            '4556015886206505': 'VISA',
            '4539048040151731': 'VISA',
            '4024007198964305': 'VISA',
            '4716175187624512': 'VISA',

            '5280934283171080': 'MASTERCARD',
            '5456060454627409': 'MASTERCARD',
            '5331113404316994': 'MASTERCARD',
            '5259474113320034': 'MASTERCARD',
            '5442179619690834': 'MASTERCARD',

            '6011894492395579': 'DISCOVER',
            '6011388644154687': 'DISCOVER',
            '6011880085013612': 'DISCOVER',
            '6011652795433988': 'DISCOVER',
            '6011375973328347': 'DISCOVER',

            '345936346788903': 'AMEX',
            '377669501013152': 'AMEX',
            '373083634595479': 'AMEX',
            '370710819865268': 'AMEX',
            '371095063560404': 'AMEX'
        };

        Object.keys(cards).forEach(function(number) {
            it('should detect card ' + number + ' as ' + cards[number], function() {
                Basket.detectCardType(number).should.equal(cards[number]);
            });
        });
    });
});

1
@ jolly.exe - Ваша скрипка повертається невизначеною для всіх тестів. Не працює :(
ShadeTreeDeveloper

@ShadeTreeDeveloper просто введіть будь-яке значення, наприклад. 372176090165471 для AMAX у текстовому полі
код шпигуна

@ jolly.exe Я бачу ... Я сподівався на те, що сформується під час введення тексту (від події клавіатури). Загадка спрацьовує, коли я ввожу повне число.
ShadeTreeDeveloper

Я закінчив писати цей біт коду, щоб зробити вхідне форматування та перевірку, яку я хотів. quercusv.github.io/smartForm
ShadeTreeDeveloper

чи знаєте ви, як виявити номери карток v-pay та bancontact? Спасибі
Олександр IY

38

Оновлено: 15 червня 2016 року (як остаточне рішення)

Будь ласка, зауважте, що я навіть даю голос за той, хто проголосує найкраще, але для того, щоб зрозуміти, що ці підсумки дійсно працюють, я перевірив його тисячами реальних BIN-кодів. Найголовніше - використовувати початкові рядки (^), інакше це дасть помилкові результати в реальному світі!

JCB ^(?:2131|1800|35)[0-9]{0,}$ Почніть з: 2131, 1800, 35 (3528-3589)

American Express ^3[47][0-9]{0,}$ Почніть з: 34, 37

Diners Club ^3(?:0[0-59]{1}|[689])[0-9]{0,}$ Почніть з: 300-305, 309, 36, 38-39

Віза ^4[0-9]{0,}$ Почніть з: 4

MasterCard ^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$ Почніть з: 2221-2720, 51-55

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro завжди зростає в діапазоні: 60-69 , починається з / не чогось іншого, але починаючи з 5, все одно потрібно закодувати як майстер-карту. Карти Maestro повинні бути виявлені в кінці коду, оскільки деякі інші мають діапазон 60-69. Будь ласка, подивіться на код.

Відкрийте для себе ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ Відкрийте для себе досить складно кодування, почніть з: 6011, 622126-622925, 644-649, 65

У JavaScript я використовую цю функцію. Це добре, коли ви призначаєте його події onkeyup, і це дає результат якнайшвидше.

function cc_brand_id(cur_val) {
    // the regular expressions check for possible matches as you type, hence the OR operators based on the number of chars
    // regexp string length {0} provided for soonest detection of beginning of the card numbers this way it could be used for BIN CODE detection also

    //JCB
    jcb_regex = new RegExp('^(?:2131|1800|35)[0-9]{0,}$'); //2131, 1800, 35 (3528-3589)
    // American Express
    amex_regex = new RegExp('^3[47][0-9]{0,}$'); //34, 37
    // Diners Club
    diners_regex = new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}$'); //300-305, 309, 36, 38-39
    // Visa
    visa_regex = new RegExp('^4[0-9]{0,}$'); //4
    // MasterCard
    mastercard_regex = new RegExp('^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$'); //2221-2720, 51-55
    maestro_regex = new RegExp('^(5[06789]|6)[0-9]{0,}$'); //always growing in the range: 60-69, started with / not something else, but starting 5 must be encoded as mastercard anyway
    //Discover
    discover_regex = new RegExp('^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$');
    ////6011, 622126-622925, 644-649, 65


    // get rid of anything but numbers
    cur_val = cur_val.replace(/\D/g, '');

    // checks per each, as their could be multiple hits
    //fix: ordering matter in detection, otherwise can give false results in rare cases
    var sel_brand = "unknown";
    if (cur_val.match(jcb_regex)) {
        sel_brand = "jcb";
    } else if (cur_val.match(amex_regex)) {
        sel_brand = "amex";
    } else if (cur_val.match(diners_regex)) {
        sel_brand = "diners_club";
    } else if (cur_val.match(visa_regex)) {
        sel_brand = "visa";
    } else if (cur_val.match(mastercard_regex)) {
        sel_brand = "mastercard";
    } else if (cur_val.match(discover_regex)) {
        sel_brand = "discover";
    } else if (cur_val.match(maestro_regex)) {
        if (cur_val[0] == '5') { //started 5 must be mastercard
            sel_brand = "mastercard";
        } else {
            sel_brand = "maestro"; //maestro is all 60-69 which is not something else, thats why this condition in the end
        }
    }

    return sel_brand;
}

Тут ви можете пограти з ним:

http://jsfiddle.net/upN3L/69/

Для PHP, що використовує цю функцію, це також виявляє деякі суб VISA / MC карт:

/**
  * Obtain a brand constant from a PAN
  *
  * @param string $pan               Credit card number
  * @param bool   $include_sub_types Include detection of sub visa brands
  * @return string
  */
public static function getCardBrand($pan, $include_sub_types = false)
{
    //maximum length is not fixed now, there are growing number of CCs has more numbers in length, limiting can give false negatives atm

    //these regexps accept not whole cc numbers too
    //visa
    $visa_regex = "/^4[0-9]{0,}$/";
    $vpreca_regex = "/^428485[0-9]{0,}$/";
    $postepay_regex = "/^(402360|402361|403035|417631|529948){0,}$/";
    $cartasi_regex = "/^(432917|432930|453998)[0-9]{0,}$/";
    $entropay_regex = "/^(406742|410162|431380|459061|533844|522093)[0-9]{0,}$/";
    $o2money_regex = "/^(422793|475743)[0-9]{0,}$/";

    // MasterCard
    $mastercard_regex = "/^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$/";
    $maestro_regex = "/^(5[06789]|6)[0-9]{0,}$/";
    $kukuruza_regex = "/^525477[0-9]{0,}$/";
    $yunacard_regex = "/^541275[0-9]{0,}$/";

    // American Express
    $amex_regex = "/^3[47][0-9]{0,}$/";

    // Diners Club
    $diners_regex = "/^3(?:0[0-59]{1}|[689])[0-9]{0,}$/";

    //Discover
    $discover_regex = "/^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$/";

    //JCB
    $jcb_regex = "/^(?:2131|1800|35)[0-9]{0,}$/";

    //ordering matter in detection, otherwise can give false results in rare cases
    if (preg_match($jcb_regex, $pan)) {
        return "jcb";
    }

    if (preg_match($amex_regex, $pan)) {
        return "amex";
    }

    if (preg_match($diners_regex, $pan)) {
        return "diners_club";
    }

    //sub visa/mastercard cards
    if ($include_sub_types) {
        if (preg_match($vpreca_regex, $pan)) {
            return "v-preca";
        }
        if (preg_match($postepay_regex, $pan)) {
            return "postepay";
        }
        if (preg_match($cartasi_regex, $pan)) {
            return "cartasi";
        }
        if (preg_match($entropay_regex, $pan)) {
            return "entropay";
        }
        if (preg_match($o2money_regex, $pan)) {
            return "o2money";
        }
        if (preg_match($kukuruza_regex, $pan)) {
            return "kukuruza";
        }
        if (preg_match($yunacard_regex, $pan)) {
            return "yunacard";
        }
    }

    if (preg_match($visa_regex, $pan)) {
        return "visa";
    }

    if (preg_match($mastercard_regex, $pan)) {
        return "mastercard";
    }

    if (preg_match($discover_regex, $pan)) {
        return "discover";
    }

    if (preg_match($maestro_regex, $pan)) {
        if ($pan[0] == '5') { //started 5 must be mastercard
            return "mastercard";
        }
        return "maestro"; //maestro is all 60-69 which is not something else, thats why this condition in the end

    }

    return "unknown"; //unknown for this system
}

1
І зверніть увагу, що це лише виявлення номера CC, а не перевірка. Це відокремлено, має бути перевірка Луна ...
Janos Szabo

Де знаходиться Visa Electron і чому Maestro перевіряє повернення MasterCard в деяких випадках? Чи не повинен MasterCard перевірити це сам?
BadHorsie

Він не вдається розпізнати цей тестовий номер JCB як будь-який із типів (3088514174175777) і ідентифікує цей тестовий номер JCB як diners_club (3096278649822922). Припустимо, що цей список номерів тестових карт дійсний у будь-якому випадку ( freeformatter.com/credit-card-number-generator-validator.html )
Дрю

немає жодної документації, що починаючи з 308 або 309 могла бути картка JCB
Janos Szabo

+1 для надання коду виявлення типу cc, що саме ти зазвичай хочеш зробити для ux - регулярний вираз для нового діапазону в MC потребує невеликого твінку: / ^ (5 [1-5] | 222 [1-9] | 22 [3-9] [0-9] | 2 [3-6] [0-9] {2} | 27 [01] [0-9] | 2720) [0-9] {0,} $ /
кінакута

21
public string GetCreditCardType(string CreditCardNumber)
{
    Regex regVisa = new Regex("^4[0-9]{12}(?:[0-9]{3})?$");
    Regex regMaster = new Regex("^5[1-5][0-9]{14}$");
    Regex regExpress = new Regex("^3[47][0-9]{13}$");
    Regex regDiners = new Regex("^3(?:0[0-5]|[68][0-9])[0-9]{11}$");
    Regex regDiscover = new Regex("^6(?:011|5[0-9]{2})[0-9]{12}$");
    Regex regJCB = new Regex("^(?:2131|1800|35\\d{3})\\d{11}$");


    if (regVisa.IsMatch(CreditCardNumber))
        return "VISA";
    else if (regMaster.IsMatch(CreditCardNumber))
        return "MASTER";
    else  if (regExpress.IsMatch(CreditCardNumber))
        return "AEXPRESS";
    else if (regDiners.IsMatch(CreditCardNumber))
        return "DINERS";
    else if (regDiscover.IsMatch(CreditCardNumber))
        return "DISCOVERS";
    else if (regJCB.IsMatch(CreditCardNumber))
        return "JCB";
    else
        return "invalid";
}

Ось функція перевірки типу кредитної картки за допомогою Regex, c #


19

Заціни:

http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CC70060A01B

function isValidCreditCard(type, ccnum) {
    /* Visa: length 16, prefix 4, dashes optional.
    Mastercard: length 16, prefix 51-55, dashes optional.
    Discover: length 16, prefix 6011, dashes optional.
    American Express: length 15, prefix 34 or 37.
    Diners: length 14, prefix 30, 36, or 38. */

    var re = new Regex({
        "visa": "/^4\d{3}-?\d{4}-?\d{4}-?\d",
        "mc": "/^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/",
        "disc": "/^6011-?\d{4}-?\d{4}-?\d{4}$/",
        "amex": "/^3[47]\d{13}$/",
        "diners": "/^3[068]\d{12}$/"
    }[type.toLowerCase()])

    if (!re.test(ccnum)) return false;
    // Remove all dashes for the checksum checks to eliminate negative numbers
    ccnum = ccnum.split("-").join("");
    // Checksum ("Mod 10")
    // Add even digits in even length strings or odd digits in odd length strings.
    var checksum = 0;
    for (var i = (2 - (ccnum.length % 2)); i <= ccnum.length; i += 2) {
        checksum += parseInt(ccnum.charAt(i - 1));
    }
    // Analyze odd digits in even length strings or even digits in odd length strings.
    for (var i = (ccnum.length % 2) + 1; i < ccnum.length; i += 2) {
        var digit = parseInt(ccnum.charAt(i - 1)) * 2;
        if (digit < 10) { checksum += digit; } else { checksum += (digit - 9); }
    }
    if ((checksum % 10) == 0) return true;
    else return false;
}

15

останнім часом мені потрібна така функціональність, я пересилав валідатор Zend Framework Credit Validator на рубін. ruby gem: https://github.com/Fivell/credit_card_validations zend Framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

Вони обидва використовують діапазони INN для виявлення типу. Тут ви можете прочитати про ІНН

Згідно з цим ви можете виявити кредитну карту альтернативно (без регулярних виразів, але декларуючи деякі правила щодо префіксів та можливої ​​довжини)

Тож у нас є наступні правила для більшості використовуваних карт

########  most used brands #########

    visa: [
        {length: [13, 16], prefixes: ['4']}
    ],
    mastercard: [
        {length: [16], prefixes: ['51', '52', '53', '54', '55']}
    ],

    amex: [
        {length: [15], prefixes: ['34', '37']}
    ],
    ######## other brands ########
    diners: [
        {length: [14], prefixes: ['300', '301', '302', '303', '304', '305', '36', '38']},
    ],

    #There are Diners Club (North America) cards that begin with 5. These are a joint venture between Diners Club and MasterCard, and are processed like a MasterCard
    # will be removed in next major version

    diners_us: [
        {length: [16], prefixes: ['54', '55']}
    ],

    discover: [
        {length: [16], prefixes: ['6011', '644', '645', '646', '647', '648',
                                  '649', '65']}
    ],

    jcb: [
        {length: [16], prefixes: ['3528', '3529', '353', '354', '355', '356', '357', '358', '1800', '2131']}
    ],


    laser: [
        {length: [16, 17, 18, 19], prefixes: ['6304', '6706', '6771']}
    ],

    solo: [
        {length: [16, 18, 19], prefixes: ['6334', '6767']}
    ],

    switch: [
        {length: [16, 18, 19], prefixes: ['633110', '633312', '633304', '633303', '633301', '633300']}

    ],

    maestro: [
        {length: [12, 13, 14, 15, 16, 17, 18, 19], prefixes: ['5010', '5011', '5012', '5013', '5014', '5015', '5016', '5017', '5018',
                                                              '502', '503', '504', '505', '506', '507', '508',
                                                              '6012', '6013', '6014', '6015', '6016', '6017', '6018', '6019',
                                                              '602', '603', '604', '605', '6060',
                                                              '677', '675', '674', '673', '672', '671', '670',
                                                              '6760', '6761', '6762', '6763', '6764', '6765', '6766', '6768', '6769']}
    ],

    # Luhn validation are skipped for union pay cards because they have unknown generation algoritm
    unionpay: [
        {length: [16, 17, 18, 19], prefixes: ['622', '624', '625', '626', '628'], skip_luhn: true}
    ],

    dankrot: [
        {length: [16], prefixes: ['5019']}
    ],

    rupay: [
        {length: [16], prefixes: ['6061', '6062', '6063', '6064', '6065', '6066', '6067', '6068', '6069', '607', '608'], skip_luhn: true}
    ]

}

Тоді за допомогою пошуку префікса та порівняння довжини ви можете виявити бренд кредитної картки. Також не забувайте про алгоритм luhn (він описаний тут http://en.wikipedia.org/wiki/Luhn ).

ОНОВЛЕННЯ

оновлений список правил можна знайти тут https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml


2
Дуже показовий. Карти VISA можуть тривати 13 цифр.
Герман Кан

@HermanKan, жоден веб-сайт VISA не говорить про те, що це має бути тривалість 16, я думаю, давно це могло бути 13, але не сьогодні
Fivell

1
Я думаю, що це підтримка спадщини
Fivell

1
@HermanKan, є ще одне, у VISA є картки VPay, і згідно з wikipedia Бренд Visa VPay може вказати довжину ПАН від 13 до 19 цифр, тому кількість карт більше 16 цифр.
Fivell

1
@Ethan, перевіри останнє посилання в моїй оновленій відповіді raw.githubusercontent.com/Fivell/credit_card_validations/master/…
Fivell

13

Ось повний код C # або VB для всіх видів речей, пов'язаних з CC, у кодовому проекті.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • ПроходитьLuhnTest

Цю статтю розглядали вже пару років, без негативних коментарів.


1
@barett - виправлено. схоже, вони перенесли його з категорії "aspnet" у категорію "перевірка", яка змінила посилання
Simon_Weaver

2
Посилання розірвано. Може, це та сама утиліта? codeproject.com/Articles/20271/…
Джош Ное

Цей код коду проекту з 2007 року. Попередження, він може бути застарілим.
арон

8

Компактна версія JavaScript

    var getCardType = function (number) {
        var cards = {
            visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
            mastercard: /^5[1-5][0-9]{14}$/,
            amex: /^3[47][0-9]{13}$/,
            diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
            discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
            jcb: /^(?:2131|1800|35\d{3})\d{11}$/
        };
        for (var card in cards) {
            if (cards[card].test(number)) {
                return card;
            }
        }
    };

8

Відповідь Анатолія в PHP:

 public static function detectCardType($num)
 {
    $re = array(
        "visa"       => "/^4[0-9]{12}(?:[0-9]{3})?$/",
        "mastercard" => "/^5[1-5][0-9]{14}$/",
        "amex"       => "/^3[47][0-9]{13}$/",
        "discover"   => "/^6(?:011|5[0-9]{2})[0-9]{12}$/",
    );

    if (preg_match($re['visa'],$num))
    {
        return 'visa';
    }
    else if (preg_match($re['mastercard'],$num))
    {
        return 'mastercard';
    }
    else if (preg_match($re['amex'],$num))
    {
        return 'amex';
    }
    else if (preg_match($re['discover'],$num))
    {
        return 'discover';
    }
    else
    {
        return false;
    }
 }

7

Ось функція класу php повертає CCtype від CCnumber.
Цей код не підтверджує карту або не виконує алгоритм Луна, лише спробуйте знайти тип кредитної картки на основі таблиці на цій сторінці . в основному використовує довжину CCnumber та префікс CCcard для визначення типу CCcard.

<?php
class CreditcardType
{
    public static $creditcardTypes = [
        [
            'Name' => 'American Express',
            'cardLength' => [15],
            'cardPrefix' => ['34', '37'],
        ], [
            'Name' => 'Maestro',
            'cardLength' => [12, 13, 14, 15, 16, 17, 18, 19],
            'cardPrefix' => ['5018', '5020', '5038', '6304', '6759', '6761', '6763'],
        ], [
            'Name' => 'Mastercard',
            'cardLength' => [16],
            'cardPrefix' => ['51', '52', '53', '54', '55'],
        ], [
            'Name' => 'Visa',
            'cardLength' => [13, 16],
            'cardPrefix' => ['4'],
        ], [
            'Name' => 'JCB',
            'cardLength' => [16],
            'cardPrefix' => ['3528', '3529', '353', '354', '355', '356', '357', '358'],
        ], [
            'Name' => 'Discover',
            'cardLength' => [16],
            'cardPrefix' => ['6011', '622126', '622127', '622128', '622129', '62213','62214', '62215', '62216', '62217', '62218', '62219','6222', '6223', '6224', '6225', '6226', '6227', '6228','62290', '62291', '622920', '622921', '622922', '622923','622924', '622925', '644', '645', '646', '647', '648','649', '65'],
        ], [
            'Name' => 'Solo',
            'cardLength' => [16, 18, 19],
            'cardPrefix' => ['6334', '6767'],
        ], [
            'Name' => 'Unionpay',
            'cardLength' => [16, 17, 18, 19],
            'cardPrefix' => ['622126', '622127', '622128', '622129', '62213', '62214','62215', '62216', '62217', '62218', '62219', '6222', '6223','6224', '6225', '6226', '6227', '6228', '62290', '62291','622920', '622921', '622922', '622923', '622924', '622925'],
        ], [
            'Name' => 'Diners Club',
            'cardLength' => [14],
            'cardPrefix' => ['300', '301', '302', '303', '304', '305', '36'],
        ], [
            'Name' => 'Diners Club US',
            'cardLength' => [16],
            'cardPrefix' => ['54', '55'],
        ], [
            'Name' => 'Diners Club Carte Blanche',
            'cardLength' => [14],
            'cardPrefix' => ['300', '305'],
        ], [
            'Name' => 'Laser',
            'cardLength' => [16, 17, 18, 19],
            'cardPrefix' => ['6304', '6706', '6771', '6709'],
        ],
    ];

    public static function getType($CCNumber)
    {
        $CCNumber = trim($CCNumber);
        $type = 'Unknown';
        foreach (CreditcardType::$creditcardTypes as $card) {
            if (! in_array(strlen($CCNumber), $card['cardLength'])) {
                continue;
            }
            $prefixes = '/^(' . implode('|', $card['cardPrefix']) . ')/';
            if (preg_match($prefixes, $CCNumber) == 1) {
                $type = $card['Name'];
                break;
            }
        }
        return $type;
    }
}

6

Не намагайтеся виявити тип кредитної картки як частину обробки платежу. Ви ризикуєте відхилити дійсні транзакції.

Якщо вам потрібно надати інформацію своєму платіжному процесору (наприклад, об’єкт кредитної картки PayPal вимагає назвати тип картки ), то вгадайте її з найменшої інформації, наприклад

$credit_card['pan'] = preg_replace('/[^0-9]/', '', $credit_card['pan']);
$inn = (int) mb_substr($credit_card['pan'], 0, 2);

// @see http://en.wikipedia.org/wiki/List_of_Bank_Identification_Numbers#Overview
if ($inn >= 40 && $inn <= 49) {
    $type = 'visa';
} else if ($inn >= 51 && $inn <= 55) {
    $type = 'mastercard';
} else if ($inn >= 60 && $inn <= 65) {
    $type = 'discover';
} else if ($inn >= 34 && $inn <= 37) {
    $type = 'amex';
} else {
    throw new \UnexpectedValueException('Unsupported card type.');
}

Такої реалізації (з використанням лише перших двох цифр) достатньо для виявлення всіх основних (а у випадку PayPal - усіх підтримуваних) схем карт. Насправді, ви можете повністю пропустити виняток та встановити за замовчуванням найпопулярніший тип картки. Нехай шлюз / процесор платежу повідомить вам, чи є помилка перевірки у відповідь на ваш запит.

Реальність така, що ваш шлюз платежів не піклується про надану вами вартість .


1
Це просто неправда. Мені відомо 3 різних провайдерів, які DO вимагають передачі типів карт, і якщо ви не передасте їх, транзакція не відбудеться.
Ed DeGagne

3
@EdDeGagne - "байдуже, яке значення" - це не те саме, що "не хвилює, якщо передано".
Квентін Скусен

Де я вказав і те, і інше? Я просто зазначив, що є провайдери, які використовуються, які вимагають ВАС пройти тип CC, більше нічого.
Ed DeGagne

Ви не можете спростити цю складну проблему, але зазвичай провайдери платежів не вимагають, щоб Ви пропонували тип картки, у них є власний метод виявлення
Janos Szabo

6

Перші номери кредитної картки можна використовувати для наближення до постачальника:

  • Віза: 49,44 або 47
  • Електрон Visa: 42, 45, 48, 49
  • MasterCard: 51
  • Амекс: 34
  • Вечеря: 30, 36, 38
  • JCB: 35

Ці діапазони були в основному оновлені, компанії-постачальники карт додали набагато більше діапазонів, ніж було зазначено у публікації.
NJInamdar

6

У програмі розпізнавання діапазону карт (CRR) недоліком алгоритмів, які використовують серію регулярних виразів або інших жорстко закодованих діапазонів, є те, що BIN / IIN змінюються з часом у моєму досвіді. Спільне брендування карт - постійне ускладнення. Різні покупці / торговці картками можуть вимагати, щоб ви ставились до однієї і тієї ж картки по-різному, залежно від геолокації, наприклад

Крім того, в останні кілька років, наприклад, з картками UnionPay в більш широкому тиражі, існуючі моделі не справляються з новими діапазонами, які іноді переплітаються з більш широкими діапазонами, які вони витісняють.
Знання географії, яку має охоплювати ваша система, може допомогти, оскільки деякі діапазони обмежуються для використання в певних країнах. Наприклад, діапазони 62 включають деякі піддіапазони AAA у США, але якщо ваша торгова база знаходиться поза межами США, ви, можливо, зможете розглянути всі 62 як UnionPay.
Вас також можуть попросити поставитися до картки по-різному, залежно від місцезнаходження продавця. Наприклад, до певних карток Великобританії слід ставитися як до дебетових на внутрішньому ринку, але як міжнародних кредитів.

Існує дуже корисний набір правил, який підтримує один великий банк-еквайр. Наприклад, https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf та https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf . (Дійсні посилання станом на червень 2017 року, завдяки користувачеві, який надав посилання на оновлену довідку.) Але пам’ятайте про застереження, що, хоча ці правила CRR можуть представляти всесвіт, що видає картки, як це стосується торговців, придбаних цим суб'єктом господарювання, він не включає, наприклад, діапазони, ідентифіковані як CUP / UPI.

Ці коментарі стосуються сценаріїв магнітної смуги (MagStripe) або PKE (Pan Key Entry). У світі ICC / EMV ситуація знову відрізняється.

Оновлення: інші відповіді на цій сторінці (а також пов'язана сторінка WikiPedia) мають JCB, як завжди, 16. Однак у моїй компанії у нас є спеціалізована команда інженерів, які сертифікують наші POS-пристрої та програмне забезпечення у кількох банках та географіях. Найновіший пакет сертифікаційних карток, який ця команда отримав від JCB, мав пропуск для 19 довгих PAN.


Привіт @CaiqueOliveira, дивіться оновлені посилання. Дякуємо mac9416, який надав посилання на оновлену посилання на BIN-правила.
MikeRoger

1
Дякуємо @ mac9416, за оновлену довідку про BIN-правила.
MikeRoger

5

Swift 2.1 Версія відповіді Usman Y. Використовуйте оператор друку для підтвердження дзвінка за значенням рядка

print(self.validateCardType(self.creditCardField.text!))

func validateCardType(testCard: String) -> String {

    let regVisa = "^4[0-9]{12}(?:[0-9]{3})?$"
    let regMaster = "^5[1-5][0-9]{14}$"
    let regExpress = "^3[47][0-9]{13}$"
    let regDiners = "^3(?:0[0-5]|[68][0-9])[0-9]{11}$"
    let regDiscover = "^6(?:011|5[0-9]{2})[0-9]{12}$"
    let regJCB = "^(?:2131|1800|35\\d{3})\\d{11}$"


    let regVisaTest = NSPredicate(format: "SELF MATCHES %@", regVisa)
    let regMasterTest = NSPredicate(format: "SELF MATCHES %@", regMaster)
    let regExpressTest = NSPredicate(format: "SELF MATCHES %@", regExpress)
    let regDinersTest = NSPredicate(format: "SELF MATCHES %@", regDiners)
    let regDiscoverTest = NSPredicate(format: "SELF MATCHES %@", regDiscover)
    let regJCBTest = NSPredicate(format: "SELF MATCHES %@", regJCB)


    if regVisaTest.evaluateWithObject(testCard){
        return "Visa"
    }
    else if regMasterTest.evaluateWithObject(testCard){
        return "MasterCard"
    }

    else if regExpressTest.evaluateWithObject(testCard){
        return "American Express"
    }

    else if regDinersTest.evaluateWithObject(testCard){
        return "Diners Club"
    }

    else if regDiscoverTest.evaluateWithObject(testCard){
        return "Discover"
    }

    else if regJCBTest.evaluateWithObject(testCard){
        return "JCB"
    }

    return ""

}

4

Stripe надав цю фантастичну бібліотеку javascript для виявлення схеми карт. Дозвольте додати кілька фрагментів коду та покажу, як ним користуватися.

По-перше, включіть його на свою веб-сторінку як

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.payment/1.2.3/jquery.payment.js " ></script>

По-друге, використовуйте функцію cardType для виявлення схеми карти.

$(document).ready(function() {              
            var type = $.payment.cardType("4242 4242 4242 4242"); //test card number
            console.log(type);                                   
}); 

Ось посилання на посилання на додаткові приклади та демонстрації.

  1. Блог смуги для jquery.payment.js
  2. Сховище Github

4

Швидко можна створити перерахунок для виявлення типу кредитної картки.

enum CreditCardType: Int { // Enum which encapsulates different card types and method to find the type of card.

case Visa
case Master
case Amex
case Discover

func validationRegex() -> String {
    var regex = ""
    switch self {
    case .Visa:
        regex = "^4[0-9]{6,}$"

    case .Master:
        regex = "^5[1-5][0-9]{5,}$"

    case .Amex:
        regex = "^3[47][0-9]{13}$"

    case .Discover:
        regex = "^6(?:011|5[0-9]{2})[0-9]{12}$"
    }

    return regex
}

func validate(cardNumber: String) -> Bool {
    let predicate = NSPredicate(format: "SELF MATCHES %@", validationRegex())
    return predicate.evaluateWithObject(cardNumber)
}

// Method returns the credit card type for given card number
static func cardTypeForCreditCardNumber(cardNumber: String) -> CreditCardType?  {
    var creditCardType: CreditCardType?

    var index = 0
    while let cardType = CreditCardType(rawValue: index) {
        if cardType.validate(cardNumber) {
            creditCardType = cardType
            break
        } else {
            index++
        }
    }
    return creditCardType
  }
}

Викличте метод CreditCardType.cardTypeForCreditCardNumber ("# номер картки"), який повертає значення перерахунку CreditCardType.


3

Моє рішення з jQuery:

function detectCreditCardType() {
    var type = new Array;
    type[1] = '^4[0-9]{12}(?:[0-9]{3})?$';      // visa
    type[2] = '^5[1-5][0-9]{14}$';              // mastercard
    type[3] = '^6(?:011|5[0-9]{2})[0-9]{12}$';  // discover
    type[4] = '^3[47][0-9]{13}$';               // amex

    var ccnum = $('.creditcard').val().replace(/[^\d.]/g, '');
    var returntype = 0;

    $.each(type, function(idx, re) {
        var regex = new RegExp(re);
        if(regex.test(ccnum) && idx>0) {
            returntype = idx;
        }
    });

    return returntype;
}

У разі повернення 0 тип кредитної картки не виявлено.

До поля введення кредитної картки слід додати клас "кредитна картка".


1
Варіація існуючих відповідей.
Gajus

1
Так, я використав код із наведених вище відповідей, ВДОСКОНАЛИ його та розмістив тут. Дякуємо за присутність ...
ZurabWeb

3
Ви повинні (а) запропонувати це як покращення існуючого коду, (b) написати відповідні внески або (c) посилатися на джерела, які використовували для написання регулярних виразів.
Гаджус

1
Гаджусе, я вважаю, що я допоміг громаді так, як міг у той момент, будь ласка, перестань говорити мені, що я мав щось зробити для когось. Я зробив те, що хоч міг бути корисним.
ZurabWeb

3

Я досить багато шукав для форматування кредитної картки та форматування номера телефону. Знайшов багато корисних порад, але нічого не відповідало моїм точним бажанням, тому я створив цей біт коду . Ви використовуєте його так:

var sf = smartForm.formatCC(myInputString);
var cardType = sf.cardType;

2
// abobjects.com, parvez ahmad ab bulk mailer
use below script

function isValidCreditCard2(type, ccnum) {
       if (type == "Visa") {
          // Visa: length 16, prefix 4, dashes optional.
          var re = /^4\d{3}?\d{4}?\d{4}?\d{4}$/;
       } else if (type == "MasterCard") {
          // Mastercard: length 16, prefix 51-55, dashes optional.
          var re = /^5[1-5]\d{2}?\d{4}?\d{4}?\d{4}$/;
       } else if (type == "Discover") {
          // Discover: length 16, prefix 6011, dashes optional.
          var re = /^6011?\d{4}?\d{4}?\d{4}$/;
       } else if (type == "AmEx") {
          // American Express: length 15, prefix 34 or 37.
          var re = /^3[4,7]\d{13}$/;
       } else if (type == "Diners") {
          // Diners: length 14, prefix 30, 36, or 38.
          var re = /^3[0,6,8]\d{12}$/;
       }
       if (!re.test(ccnum)) return false;
       return true;
       /*
       // Remove all dashes for the checksum checks to eliminate negative numbers
       ccnum = ccnum.split("-").join("");
       // Checksum ("Mod 10")
       // Add even digits in even length strings or odd digits in odd length strings.
       var checksum = 0;
       for (var i=(2-(ccnum.length % 2)); i<=ccnum.length; i+=2) {
          checksum += parseInt(ccnum.charAt(i-1));
       }
       // Analyze odd digits in even length strings or even digits in odd length strings.
       for (var i=(ccnum.length % 2) + 1; i<ccnum.length; i+=2) {
          var digit = parseInt(ccnum.charAt(i-1)) * 2;
          if (digit < 10) { checksum += digit; } else { checksum += (digit-9); }
       }
       if ((checksum % 10) == 0) return true; else return false;
       */

    }
jQuery.validator.addMethod("isValidCreditCard", function(postalcode, element) { 
    return isValidCreditCard2($("#cardType").val(), $("#cardNum").val()); 

}, "<br>credit card is invalid");


     Type</td>
                                          <td class="text">&nbsp; <form:select path="cardType" cssclass="fields" style="border: 1px solid #D5D5D5;padding: 0px 0px 0px 0px;width: 130px;height: 22px;">
                                              <option value="SELECT">SELECT</option>
                                              <option value="MasterCard">Mastercard</option>
                                              <option value="Visa">Visa</option>
                                               <option value="AmEx">American Express</option>
                                              <option value="Discover">Discover</option>
                                            </form:select> <font color="#FF0000">*</font> 

$("#signupForm").validate({

    rules:{
       companyName:{required: true},
       address1:{required: true},
       city:{required: true},
       state:{required: true},
       zip:{required: true},
       country:{required: true},
       chkAgree:{required: true},
       confPassword:{required: true},
       lastName:{required: true},
       firstName:{required: true},
       ccAddress1:{required: true},
       ccZip:{         
           postalcode : true
       },
       phone:{required: true},
       email:{
           required: true,
           email: true
           },
       userName:{
           required: true,
           minlength: 6
           },
       password:{
           required: true,
           minlength: 6
           },          
       cardNum:{           
            isValidCreditCard : true
       },

Питання стосується алгоритму перевірки кредитної картки, а не конкретної реалізації. Що робить цей код?
Еміль Вікстрем

2

Лише маленькою ложкою годування:

$("#CreditCardNumber").focusout(function () {


        var regVisa = /^4[0-9]{12}(?:[0-9]{3})?$/;
        var regMasterCard = /^5[1-5][0-9]{14}$/;
        var regAmex = /^3[47][0-9]{13}$/;
        var regDiscover = /^6(?:011|5[0-9]{2})[0-9]{12}$/;

        if (regVisa.test($(this).val())) {
            $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/visa.png")'>");          

        }

        else if (regMasterCard.test($(this).val())) {
        $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/mastercard.png")'>");

        }

        else if (regAmex.test($(this).val())) {

           $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/amex.png")'>");

        }
         else if (regDiscover.test($(this).val())) {

           $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/discover.png")'>");

        }
        else {
        $("#CCImage").html("NA");

        }

    });

2

Ось приклад деяких булевих функцій, написаних на Python, які повертаються, Trueякщо карта виявлена ​​відповідно до імені функції.

def is_american_express(cc_number):
    """Checks if the card is an american express. If us billing address country code, & is_amex, use vpos
    https://en.wikipedia.org/wiki/Bank_card_number#cite_note-GenCardFeatures-3
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^3[47][0-9]{13}$', cc_number))


def is_visa(cc_number):
    """Checks if the card is a visa, begins with 4 and 12 or 15 additional digits.
    :param cc_number: unicode card number
    """

    # Standard Visa is 13 or 16, debit can be 19
    if bool(re.match(r'^4', cc_number)) and len(cc_number) in [13, 16, 19]:
        return True

    return False


def is_mastercard(cc_number):
    """Checks if the card is a mastercard. Begins with 51-55 or 2221-2720 and 16 in length.
    :param cc_number: unicode card number
    """
    if len(cc_number) == 16 and cc_number.isdigit():  # Check digit, before cast to int
        return bool(re.match(r'^5[1-5]', cc_number)) or int(cc_number[:4]) in range(2221, 2721)
    return False


def is_discover(cc_number):
    """Checks if the card is discover, re would be too hard to maintain. Not a supported card.
    :param cc_number: unicode card number
    """
    if len(cc_number) == 16:
        try:
            # return bool(cc_number[:4] == '6011' or cc_number[:2] == '65' or cc_number[:6] in range(622126, 622926))
            return bool(cc_number[:4] == '6011' or cc_number[:2] == '65' or 622126 <= int(cc_number[:6]) <= 622925)
        except ValueError:
            return False
    return False


def is_jcb(cc_number):
    """Checks if the card is a jcb. Not a supported card.
    :param cc_number: unicode card number
    """
    # return bool(re.match(r'^(?:2131|1800|35\d{3})\d{11}$', cc_number))  # wikipedia
    return bool(re.match(r'^35(2[89]|[3-8][0-9])[0-9]{12}$', cc_number))  # PawelDecowski


def is_diners_club(cc_number):
    """Checks if the card is a diners club. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^3(?:0[0-6]|[68][0-9])[0-9]{11}$', cc_number))  # 0-5 = carte blance, 6 = international


def is_laser(cc_number):
    """Checks if the card is laser. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^(6304|670[69]|6771)', cc_number))


def is_maestro(cc_number):
    """Checks if the card is maestro. Not a supported card.
    :param cc_number: unicode card number
    """
    possible_lengths = [12, 13, 14, 15, 16, 17, 18, 19]
    return bool(re.match(r'^(50|5[6-9]|6[0-9])', cc_number)) and len(cc_number) in possible_lengths


# Child cards

def is_visa_electron(cc_number):
    """Child of visa. Checks if the card is a visa electron. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^(4026|417500|4508|4844|491(3|7))', cc_number)) and len(cc_number) == 16


def is_total_rewards_visa(cc_number):
    """Child of visa. Checks if the card is a Total Rewards Visa. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^41277777[0-9]{8}$', cc_number))


def is_diners_club_carte_blanche(cc_number):
    """Child card of diners. Checks if the card is a diners club carte blance. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^30[0-5][0-9]{11}$', cc_number))  # github PawelDecowski, jquery-creditcardvalidator


def is_diners_club_carte_international(cc_number):
    """Child card of diners. Checks if the card is a diners club international. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^36[0-9]{12}$', cc_number))  # jquery-creditcardvalidator

1

Перші шість цифр номера картки (включаючи початкову цифру MII) відомі як ідентифікаційний номер емітента (IIN). Вони ідентифікують установу видачі картки, яка видала картку власнику картки. Решту номера виділяє емітент картки. Довжина номера картки - це її кількість цифр. Багато емітентів карт роздруковують весь IIN та номер рахунку на своїй картці.

Виходячи з вищенаведених фактів, я хотів би зберегти фрагмент коду JAVA, щоб визначити марку картки.

Типові типи карт

public static final String AMERICAN_EXPRESS = "American Express";
public static final String DISCOVER = "Discover";
public static final String JCB = "JCB";
public static final String DINERS_CLUB = "Diners Club";
public static final String VISA = "Visa";
public static final String MASTERCARD = "MasterCard";
public static final String UNKNOWN = "Unknown";

Префікси карт

// Based on http://en.wikipedia.org/wiki/Bank_card_number#Issuer_identification_number_.28IIN.29
public static final String[] PREFIXES_AMERICAN_EXPRESS = {"34", "37"};
public static final String[] PREFIXES_DISCOVER = {"60", "62", "64", "65"};
public static final String[] PREFIXES_JCB = {"35"};
public static final String[] PREFIXES_DINERS_CLUB = {"300", "301", "302", "303", "304", "305", "309", "36", "38", "39"};
public static final String[] PREFIXES_VISA = {"4"};
public static final String[] PREFIXES_MASTERCARD = {
        "2221", "2222", "2223", "2224", "2225", "2226", "2227", "2228", "2229",
        "223", "224", "225", "226", "227", "228", "229",
        "23", "24", "25", "26",
        "270", "271", "2720",
        "50", "51", "52", "53", "54", "55"
    };

Перевірте, чи має вхідний номер якийсь із вказаних префіксів.

public String getBrand(String number) {

String evaluatedType;
if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_AMERICAN_EXPRESS)) {
    evaluatedType = AMERICAN_EXPRESS;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_DISCOVER)) {
    evaluatedType = DISCOVER;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_JCB)) {
    evaluatedType = JCB;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_DINERS_CLUB)) {
    evaluatedType = DINERS_CLUB;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_VISA)) {
    evaluatedType = VISA;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_MASTERCARD)) {
    evaluatedType = MASTERCARD;
} else {
    evaluatedType = UNKNOWN;
}
    return evaluatedType;
}

Нарешті, метод Utility

/**
  * Check to see if the input number has any of the given prefixes.
  *
  * @param number the number to test
  * @param prefixes the prefixes to test against
  * @return {@code true} if number begins with any of the input prefixes
*/

public static boolean hasAnyPrefix(String number, String... prefixes) {
  if (number == null) {
       return false;
  }
   for (String prefix : prefixes) {
       if (number.startsWith(prefix)) {
       return true;
    }
  }
     return false;
}

Довідково


1

Спробуйте це для котлін. Додати Regex і додати до оператора if.

private fun getCardType(number: String): String {

        val visa = Regex("^4[0-9]{12}(?:[0-9]{3})?$")
        val mastercard = Regex("^5[1-5][0-9]{14}$")
        val amx = Regex("^3[47][0-9]{13}$")

        return when {
            visa.matches(number) -> "Visa"
            mastercard.matches(number) -> "Mastercard"
            amx.matches(number) -> "American Express"
            else -> "Unknown"
        }
    }

0

Правила регулярного вираження, які відповідають відповідним постачальникам карт :

  • (4\d{12}(?:\d{3})?) для візи.
  • (5[1-5]\d{14}) для MasterCard.
  • (3[47]\d{13}) для AMEX.
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) для Маестро.
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) для Diners Club.
  • (6(?:011|5[0-9]{2})[0-9]{12}) для Discover.
  • (35[2-8][89]\d\d\d{10}) для JCB.

Я думаю, що регулярний вираз для JCB невірний. Усі перші чотири цифри між 3528 і 3589 повинні бути прийняті, але 3570, наприклад, це не слід.
Гейб

0

Я використовую https://github.com/bendrucker/creditcards-types/ для виявлення типу кредитної картки за номером. Одне питання, з яким я зіткнувся, - це тестовий номер 6011 1111 1111 1117

з https://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/ ми можемо побачити, що це номер відкриття, оскільки він починається з 6011. Але результат, який я отримую від типів кредитних карт, - це "Maestro". Я відкрив питання автору. Він відповів мені дуже скоро і надав цей pdf doc https://www.discovernetwork.com/downloads/IPP_VAR_Compliance.pdf З документа видно чітко, що 6011 1111 1111 1117 не потрапляє в діапазон кредитної картки виявлення.


У мене те саме питання, ви це вирішили?
lucasvm1980

@ lucasvm1980 Я думаю, що PDF-файл Discovernetwork.com є більш надійним. А номер 6011 1111 1111 1117 - це лише тестовий номер, жодна реальна кредитна картка не має цього номера. Тому я думаю, що про це турбуватися не потрібно.
yuxiaomin

Схоже, є помилка з якоюсь карткою Discover, я спробував дійсне число, і я також отримую цю помилку.
lucasvm1980

@ lucasvm1980 Ви можете вказати номер та подати проблему на github?
yuxiaomin

0

Спробуйте це. Для швидкого.

func checkCardValidation(number : String) -> Bool
{
    let reversedInts = number.characters.reversed().map { Int(String($0)) }
        return reversedInts.enumerated().reduce(0, {(sum, val) in
            let odd = val.offset % 2 == 1
            return sum + (odd ? (val.element! == 9 ? 9 : (val.element! * 2) % 9) : val.element!)
        }) % 10 == 0
}

Використовуйте.

if (self.checkCardValidation(number: "yourNumber") == true) {
     print("Card Number valid")
}else{
     print("Card Number not valid")
}

0
follow Luhn’s algorithm

 private  boolean validateCreditCardNumber(String str) {

        int[] ints = new int[str.length()];
        for (int i = 0; i < str.length(); i++) {
            ints[i] = Integer.parseInt(str.substring(i, i + 1));
        }
        for (int i = ints.length - 2; i >= 0; i = i - 2) {
            int j = ints[i];
            j = j * 2;
            if (j > 9) {
                j = j % 10 + 1;
            }
            ints[i] = j;
        }
        int sum = 0;
        for (int i = 0; i < ints.length; i++) {
            sum += ints[i];
        }
        if (sum % 10 == 0) {
           return true;
        } else {
            return false;
        }


    }

then call this method

Edittext mCreditCardNumberEt;

 mCreditCardNumberEt.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

             int cardcount=   s.toString().length();
                 if(cardcount>=16) {
                    boolean cardnumbervalid=   validateCreditCardNumber(s.toString());
                    if(cardnumbervalid) {
                        cardvalidtesting.setText("Valid Card");
                        cardvalidtesting.setTextColor(ContextCompat.getColor(context,R.color.green));
                    }
                    else {
                        cardvalidtesting.setText("Invalid Card");
                        cardvalidtesting.setTextColor(ContextCompat.getColor(context,R.color.red));
                    }
                }
               else if(cardcount>0 &&cardcount<16) {
                     cardvalidtesting.setText("Invalid Card");
                     cardvalidtesting.setTextColor(ContextCompat.getColor(context,R.color.red));
                }

                else {
                    cardvalidtesting.setText("");

                }


                }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.