Как вы определяете тип кредитной карты по номеру?


516

Я пытаюсь выяснить, как определить тип кредитной карты, основываясь исключительно на ее номере. Кто-нибудь знает точный, надежный способ найти это?


3
Используя регулярное выражение. Проверьте эту ссылку для получения дополнительной информации.
Senfo

3
Подробности в Википедии: en.wikipedia.org/wiki/Credit_card_numbers
Стен Вестерли,

1
В Википедии есть хорошая сводная таблица по адресу en.wikipedia.org/wiki/Credit_card_numbers . Это первые от шести до шести цифр, которые указывают тип и эмитента карты.
Алекс

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

3
также кто-нибудь может прокомментировать, если эти алгоритмы хороши «на все времена» - или они периодически меняются, как, например, алгоритм «вычисления, если телефонный номер находится в Калифорнии»
Simon_Weaver

Ответы:


772

Номер кредитной / дебетовой карты называется PAN или Первичным номером счета . Первые шесть цифр PAN взяты из IIN или идентификационного номера эмитента , принадлежащего банку-эмитенту (ранее IIN назывались BIN - идентификационные номера банков - поэтому вы можете увидеть ссылки на эту терминологию в некоторых документах). Эти шесть цифр соответствуют международному стандарту ISO / IEC 7812 и могут использоваться для определения типа карты по номеру.

К сожалению, фактическая база данных ИСО / МЭК 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 цифр (для полного ИИН плюс одна контрольная цифра, которая должна соответствовать значению, предсказанному алгоритмом Луна ).

Еще один совет: перед обработкой PAN владельца карты удалите все пробелы и знаки препинания из ввода . Почему? Потому что, как правило , вводить цифры в группы гораздо проще, подобно тому, как они отображаются на лицевой стороне реальной кредитной карты, т.е.

4444 4444 4444 4444

гораздо легче правильно ввести, чем

4444444444444444

На самом деле нет смысла наказывать пользователей, потому что они вводят символы, которых вы здесь не ожидаете.

Это также означает, что в полях ввода должно быть не менее 24 символов, в противном случае пользователям, которые вводят пробелы, не хватит места. Я бы порекомендовал вам сделать поле достаточно широким, чтобы отображать 32 символа и разрешать до 64; это дает много возможностей для расширения.

Вот изображение, которое дает немного больше понимания:

ОБНОВЛЕНИЕ (2014): метод контрольной суммы больше не является допустимым способом проверки подлинности карты, как отмечено в комментариях к этому ответу.

ОБНОВЛЕНИЕ (2016): Mastercard вводит новые диапазоны BIN, начиная с Ach Payment .

Проверка кредитной карты


7
отличный пример. у вас есть регулярное выражение для карт маэстро?
Маникандан

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

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

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

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 в текстовом поле
Code Spy

@ jolly.exe Я вижу ... Я надеялся, что что-то будет форматироваться при вводе (вне события keyup). Скрипка работает, когда я ввожу полный номер.
ShadeTreeDeveloper

Я закончил тем, что написал этот фрагмент кода для форматирования и проверки ввода, которые я хотел. quercusv.github.io/smartForm
ShadeTreeDeveloper

Вы знаете, как определить номера карт V-Pay и BanContact? Спасибо
Александр IY

38

Обновлено: 15 июня 2016 г. (как окончательное решение в настоящее время)

Пожалуйста, обратите внимание, что я даже отстаиваю голос за того, за кого проголосовали лидеры, но чтобы прояснить это, на самом деле это регулярные выражения, я протестировал его с тысячами реальных кодов БИН. Самое главное - использовать стартовые строки (^), иначе это приведет к ложным результатам в реальном мире!

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

Маэстро ^(5[06789]|6)[0-9]{0,}$ Маэстро всегда растет в диапазоне: 60-69 , начинается с / не с чего-то другого, но начиная с 5, в любом случае, необходимо закодировать как mastercard. Карты 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, а не проверка. Это отделено, должна быть проверка Луна ...
Янос Сабо

Где находится Visa Electron, и почему чек Maestro в некоторых случаях возвращает MasterCard? Разве MasterCard не должен проверить это сам?
BadHorsie

Он не может распознать этот тестовый номер JCB как любой из типов (3088514174175777) и идентифицирует этот тестовый номер JCB как diners_club (3096278649822922). Предполагая, что этот список номеров тестовых карт действителен в любом случае ( freeformatter.com/credit-card-number-generator-validator.html )
Дрю

нет документации о том, что начиная с 308 или 309 может быть карта JCB
Янош Сабо

+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 на ruby. 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 algoritm (он описан здесь 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, и, согласно википедии, бренд Visa VPay может указывать длины PAN от 13 до 19 цифр, так что теперь виден номер карты из более чем 16 цифр.
Fivell

1
@Ethan, проверьте последнюю ссылку в моем обновленном ответе raw.githubusercontent.com/Fivell/credit_card_validations/master/…
Fivell

13

Вот полный код C # или VB для всех видов связанных с CC вещей в codeproject.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

Эта статья была в течение нескольких лет без негативных комментариев.


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

2
Ссылка не работает. Может быть, это та же утилита? codeproject.com/Articles/20271/…
Джош Ноу

Этот код-код проекта 2007 года. Внимание, он может быть устаревшим.
Aron

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
@EdDeGagne - «не волнует, какое значение» не то же самое, что «не волнует, если передано».
Квентин Скоусен

Где я указал либо? Я просто упомянул, что есть провайдеры, которые требуют, чтобы ВЫ передавали тип CC, не более того.
Эд ДеГань

Вы не можете упростить эту сложную проблему, но, как правило, поставщики платежных услуг не требуют от вас указания типа карты, у них есть свой собственный способ определения
Янош Сабо

6

Первые цифры кредитной карты можно использовать для приблизительного определения поставщика:

  • Виза: 49,44 или 47
  • Визовый электрон: 42, 45, 48, 49
  • MasterCard: 51
  • Amex: 34
  • Diners: 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 Версия ответа Усмана Y. Используйте оператор print для проверки, поэтому вызывайте по некоторому строковому значению

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

В swift вы можете создать перечисление для определения типа кредитной карты.

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
Вы должны были (а) предложить это как улучшение существующего кода, (б) написать соответствующий вклад или (в) ссылаться на источники, которые вы использовали для написания регулярных выражений.
Gajus

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

Наконец, Утилита метод

/**
  * 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

Попробуйте это для kotlin. Добавьте Regex и добавьте в оператор when.

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}) для Обнаружения.
  • (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 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?
Юсяньомин

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.