Como você detecta o tipo de cartão de crédito com base no número?

516

Estou tentando descobrir como detectar o tipo de cartão de crédito com base apenas no número. Alguém sabe de uma maneira definitiva e confiável de encontrar isso?

Andrew Edvalson
fonte
3
Usando uma expressão regular. Confira este link para mais informações.
senfo 16/09/08
3
Os detalhes estão todos na Wikipedia: en.wikipedia.org/wiki/Credit_card_numbers
Sten Vesterli
1
Há uma boa tabela de resumo na Wikipedia, em en.wikipedia.org/wiki/Credit_card_numbers . É o primeiro a seis dígitos que informa o tipo e o emissor do cartão.
Alex
3
Eu não usaria uma regex além de retirar o primeiro grupo numérico; geralmente, você pode dizer apenas dos 4 primeiros números (nos EUA). Também antes de se preocupar em pagar pela liberação de uma cobrança, execute uma soma de verificação Mod 10 no número do cartão para garantir que seja legítima. Algoritmo de Luhn
Dan Blair
3
Também pode alguém comentário se estes algoritmos são boas 'para sempre' - ou eles periodicamente mudança, como por exemplo, o algoritmo para 'calcular se um número de telefone está na california'
Simon_Weaver

Respostas:

772

O número do cartão de crédito / débito é conhecido como PAN ou Número da conta principal . Os seis primeiros dígitos do PAN são obtidos do IIN , ou Número de identificação do emissor , pertencente ao banco emissor (os IINs eram conhecidos anteriormente como BIN - Números de identificação bancária - para que você possa ver referências a essa terminologia em alguns documentos). Esses seis dígitos estão sujeitos a um padrão internacional, ISO / IEC 7812 , e podem ser usados ​​para determinar o tipo de cartão a partir do número.

Infelizmente, o banco de dados ISO / IEC 7812 real não está disponível ao público, no entanto, existem listas não oficiais, comerciais e gratuitas, inclusive na Wikipedia .

De qualquer forma, para detectar o tipo no número, você pode usar uma expressão regular como as abaixo: Crédito por expressões originais

Visa: os ^4[0-9]{6,}$ números dos cartões Visa começam com 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,}$ antes de 2016, os números MasterCard começam com os números 51 a 55, mas isso detectará apenas cartões de crédito MasterCard ; existem outros cartões emitidos usando o sistema MasterCard que não se enquadram nessa faixa IIN. Em 2016, eles adicionarão números no intervalo (222100-272099).

American Express: ^3[47][0-9]{5,}$ os números dos cartões American Express começam com 34 ou 37.

Diners Club: os ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ números dos cartões Diners Club começam entre 300 e 305, 36 ou 38. Existem cartões Diners Club que começam com 5 e têm 16 dígitos. Trata-se de uma joint venture entre o Diners Club e a MasterCard e deve ser processada como um MasterCard.

Descobrir: os ^6(?:011|5[0-9]{2})[0-9]{3,}$ números dos cartões Discover começam com 6011 ou 65.

JCB: os ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ cartões JCB começam com 2131, 1800 ou 35.

Infelizmente, existem vários tipos de cartões processados ​​com o sistema MasterCard que não vivem no intervalo IIN da MasterCard (números que começam 51 ... 55); o caso mais importante é o dos cartões Maestro, muitos dos quais foram emitidos pelas gamas IIN de outros bancos e, portanto, estão localizados em todo o espaço numérico. Como resultado, pode ser melhor supor que qualquer cartão que não seja de outro tipo aceito deve ser um MasterCard .

Importante : os números dos cartões variam em tamanho; por exemplo, a Visa emitiu cartões com PANs de 13 dígitos e cartões com PANs de 16 dígitos. Atualmente, a documentação da Visa indica que ela pode emitir ou ter emitido números com 12 a 19 dígitos. Portanto, você não deve verificar o comprimento do número do cartão, exceto para verificar se ele possui pelo menos 7 dígitos (para um IIN completo mais um dígito de verificação, que deve corresponder ao valor previsto pelo algoritmo de Luhn ).

Mais uma dica: antes de processar um PAN do titular do cartão, retire todos os caracteres de espaço em branco e de pontuação da entrada . Por quê? Como geralmente é muito mais fácil inserir os dígitos em grupos, semelhante à maneira como eles são exibidos na frente de um cartão de crédito real, ou seja,

4444 4444 4444 4444

é muito mais fácil entrar corretamente do que

4444444444444444

Não há realmente nenhum benefício em punir o usuário porque ele inseriu caracteres que você não espera aqui.

Isso também implica garantir que seus campos de entrada tenham espaço para pelo menos 24 caracteres; caso contrário, os usuários que inserirem espaços ficarão sem espaço. Eu recomendo que você amplie o campo o suficiente para exibir 32 caracteres e permitir até 64; isso oferece muito espaço para expansão.

Aqui está uma imagem que fornece um pouco mais de insight:

ATUALIZAÇÃO (2014): O método de soma de verificação não parece mais uma maneira válida de verificar a autenticidade de um cartão, conforme observado nos comentários desta resposta.

ATUALIZAÇÃO (2016): a Mastercard deve implementar novos intervalos de BIN a partir do Ach Payment .

verificação de cartão de credito

senfo
fonte
7
ótimo exemplo. você tem a expressão regular para cartões maestro?
Manikandan
4
Não não não. Você não pode confiar no tamanho dos números dos cartões; eles podem mudar a qualquer momento. A única parte do número do cartão em que você pode confiar é o IIN (que costumava ser chamado de BIN) e o prefixo do número. Além disso, você não pode detectar cartões Mastercard da maneira sugerida; que selecionará apenas um subconjunto de cartões processados ​​pelo sistema Mastercard (o principal problema são os cartões Maestro, que possuem uma variedade de prefixos IIN).
Alastair
2
@alastair você leu as expressões antes de comentar? Eles foram escritos especificamente para usar o IIN, então não entendo o que você está tentando dizer. Além disso, o IIN pode ser usado para identificar o emissor do cartão, mas não validar. 5412, por exemplo, não representa um MasterCard completo, mas sua sugestão implicaria que sim. Não encontrei nenhuma prova de que os MasterCards tenham apenas 16 dígitos. Sinta-se à vontade para fornecer uma fonte para sua reivindicação. Você está correto ao mencionar que uma atualização precisa ser feita para os cartões Maestro.
senfo
3
@senfo Você está certo, o 5412 não seria um número Mastercard completo. Os IINs têm seis dígitos, portanto, um número completo de cartão deve ter 7 dígitos (mínimo) e deve passar na verificação de Luhn. Não há necessidade de "prova" de que os números do Mastercard possuem algo além de 16 dígitos; o ponto é que, independentemente da situação atual, no futuro eles poderão emitir cartões com 17 ou 18 dígitos ou, com isso, alguns com 15. Confiar neles com 16 dígitos é desnecessário e cria um risco de manutenção a longo prazo.
Alastair
3
Acho muito difícil acreditar que alguns cartões válidos não teriam um dígito de verificação correto, de acordo com o algoritmo de Luhn. Usava-se absolutamente em todos os lugares para verificar os números dos cartões contra erros de digitação e tentativas de fraude. Em vez disso, observei que algumas pessoas bastante inteligentes simplesmente não entendem o algoritmo e apenas o calculam errado.
Rennex
74

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

Teste de unidade:

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]);
            });
        });
    });
});
Anatoliy
fonte
1
@ jolly.exe - Seu violino retorna indefinido para todos os testes. Não funciona :(
ShadeTreeDeveloper
@ShadeTreeDeveloper basta digitar qualquer valor, por exemplo. 372176090165471 para AMAX no campo de texto
Código Spy
@ jolly.exe Entendo ... Eu esperava algo que fosse formatado enquanto eu digitava (fora do evento keyup). O violino funciona quando digito um número inteiro.
ShadeTreeDeveloper
Acabei escrevendo esse bit de código para fazer a formatação e validação de entrada que eu queria. Quercusv.github.io/smartForm
ShadeTreeDeveloper
você sabe como detectar números de cartões v-pay e bancontact? Obrigado
Oleksandr IY
38

Atualizado: 15 de junho de 2016 (atualmente, como solução definitiva)

Por favor, note que eu até desisto de votar em quem é o mais votado, mas para deixar claro que esses são os regexps que realmente funcionam, eu testei com milhares de códigos BIN reais. O mais importante é usar as strings de início (^), caso contrário, ele fornecerá resultados falsos no mundo real!

JCB ^(?:2131|1800|35)[0-9]{0,}$ Começa com: 2131, 1800, 35 (3528-3589)

American Express ^3[47][0-9]{0,}$ Iniciar com: 34, 37

Diners Club ^3(?:0[0-59]{1}|[689])[0-9]{0,}$ Começa com: 300-305, 309, 36, 38-39

Visa ^4[0-9]{0,}$ Iniciar com: 4

MasterCard ^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$ Começa com: 2221-2720, 51-55

Maestro O ^(5[06789]|6)[0-9]{0,}$ Maestro sempre cresce no intervalo: 60-69 , iniciado com / não outra coisa, mas o início 5 deve ser codificado como mastercard de qualquer maneira. Os cartões Maestro devem ser detectados no final do código, porque outros têm no intervalo de 60 a 69. Por favor, olhe o código.

Descobrir ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ Descobrir bastante difícil de codificar, comece com: 6011, 622126-622925, 644-649, 65

Em javascript, eu uso essa função. Isso é bom quando você o atribui a um evento onkeyup e fornece o resultado o mais rápido possível.

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

Aqui você pode brincar com ele:

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

Para o PHP, use esta função, isso também detecta algumas placas sub 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
}
Janos Szabo
fonte
1
E observe que isso é apenas detecção de número CC e não validação. Que é separado, deve ser um cheque Luhn ...
Janos Szabo
Onde está a Visa Electron e por que o cheque Maestro devolve o MasterCard em alguns casos? O MasterCard não deveria verificar isso sozinho?
BadHorsie
Ele falha ao reconhecer este número de teste JCB como qualquer um dos tipos (3088514174175777) e identifica esse número JCB de teste como diners_club (3096278649822922). Assumindo esta lista de números de cartão de teste são de qualquer maneira válida ( freeformatter.com/credit-card-number-generator-validator.html )
de Drew
há nenhuma documentação que a partir de 308 ou 309 poderia ser um cartão JCB
Janos Szabo
+1 para fornecer código de detecção de tipo cc, que é o que você normalmente deseja fazer para o ux - a regex para o novo intervalo no MC precisa de uma pequena semana: / ^ (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,} $ /
kinakuta
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";
}

Aqui está a função para verificar o tipo de cartão de crédito usando Regex, c #

Usman Younas
fonte
19

Veja isso:

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;
}
Rashy
fonte
15

recentemente, eu precisava dessa funcionalidade, estava portando o Zend Framework Credit Card Validator para ruby. ruby gem: https://github.com/Fivell/credit_card_validations zend framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

Ambos usam faixas de INN para detectar o tipo. Aqui você pode ler sobre o INN

De acordo com isso, você pode detectar o cartão de crédito alternativamente (sem regexps, mas declarando algumas regras sobre prefixos e tamanho possível)

Portanto, temos as próximas regras para os cartões mais usados

########  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}
    ]

}

Pesquisando o prefixo e comparando o comprimento, você pode detectar a marca do cartão de crédito. Também não se esqueça do algoritmo luhn (é descrito aqui http://en.wikipedia.org/wiki/Luhn ).

ATUALIZAR

lista atualizada de regras pode ser encontrada aqui https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml

Fivell
fonte
2
Muito ilustrativo. Os cartões VISA podem ter 13 dígitos.
Herman Kan
@HermanKan, nenhum site VISA diz que deve ser de 16 comprimento, eu acho que há muito tempo que poderia ser 13, mas não hoje em dia
Fivell
1
Eu acho que é o legado apoio
Fivell
1
@HermanKan, há mais uma coisa: a VISA possui cartões VPay e, de acordo com a marca VPay da wikipedia, a Visa pode especificar comprimentos de PAN de 13 a 19 dígitos, para que agora seja visto um número de cartão com mais de 16 dígitos.
Fivell
1
@ Ethan, verifique o último link na minha resposta atualizada raw.githubusercontent.com/Fivell/credit_card_validations/master/…
Fivell
13

Aqui está o código C # ou VB completo para todos os tipos de coisas relacionadas ao CC no codeproject.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

Este artigo existe há alguns anos sem comentários negativos.

Simon_Weaver
fonte
1
@ barett - corrigido. parece que eles mudaram da categoria 'aspnet' para a categoria 'validation', que alterou o link
Simon_Weaver 20/08/2010
2
Link quebrado. Talvez este seja o mesmo utilitário? codeproject.com/Articles/20271/...
Josh Noe
Esse código de projeto de código é de 2007. Aviso, pode estar desatualizado.
Aron
8

Versão javascript compacta

    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;
            }
        }
    };
usuario
fonte
8

Resposta de Anatoliy em 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;
    }
 }
angelcool.net
fonte
7

Aqui está uma função de classe php retorna CCtype por CCnumber.
Este código não valida o cartão ou não executa o algoritmo Luhn, apenas tentando encontrar o tipo de cartão de crédito com base na tabela nesta página . usa basicamente o comprimento CCnumber e o prefixo CCcard para determinar o tipo de 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;
    }
}
ismail
fonte
6

Não tente detectar o tipo de cartão de crédito como parte do processamento de um pagamento. Você está arriscando recusar transações válidas.

Se você precisar fornecer informações ao seu processador de pagamento (por exemplo, o objeto do cartão de crédito do PayPal precisa nomear o tipo de cartão ), adivinhe-o com o mínimo de informações disponíveis, por exemplo

$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.');
}

Essa implementação (usando apenas os dois primeiros dígitos) é suficiente para identificar todos os principais esquemas de cartões (e no caso do PayPal todos os suportados). Na verdade, você pode ignorar a exceção completamente e usar como padrão o tipo de cartão mais popular. Deixe o gateway / processador de pagamento informar se há um erro de validação em resposta à sua solicitação.

A realidade é que seu gateway de pagamento não se importa com o valor que você fornece .

Gajus
fonte
1
Isso é simplesmente falso. Conheço três fornecedores diferentes que exigem a transferência de tipos de cartão e, se você não a transmitir, a transação falhará.
precisa saber é o seguinte
3
@ EdDeGagne - "não se importa com o valor" não é o mesmo que "não se importa se for passado".
Quentin Skousen
Onde eu especifiquei também? Eu simplesmente mencionei que existem provedores em uso que exigem que você passe no tipo CC, nada mais.
Ed DeGagne 18/08/14
você não pode simplificar esta questão complexa, mas geralmente provedores de pagamento não requerem para você sugerir o tipo de cartão, eles têm o seu próprio método para detectar
Janos Szabo
6

Os primeiros números do cartão de crédito podem ser usados ​​para aproximar o fornecedor:

  • Visto: 49,44 ou 47
  • Visa electron: 42, 45, 48, 49
  • MasterCard: 51
  • Amex: 34
  • Lanchonetes: 30, 36, 38
  • JCB: 35
Shoban
fonte
Esses intervalos foram atualizados principalmente, as empresas fornecedoras de cartões adicionaram muito mais intervalos do que o mencionado no post.
NJInamdar
6

No reconhecimento de intervalo de cartões (CRR), uma desvantagem com algoritmos que usam uma série de regex ou outros intervalos codificados é que os BINs / IINs mudam ao longo do tempo em minha experiência. O co-branding de cartões é uma complicação contínua. Os adquirentes / comerciantes de cartões diferentes podem precisar que você trate o mesmo cartão de maneira diferente, dependendo, por exemplo, da localização geográfica.

Além disso, nos últimos anos com, por exemplo, cartões UnionPay em circulação mais ampla, os modelos existentes não lidam com novos intervalos que às vezes intercalam com intervalos mais amplos que eles substituem.
Conhecer a geografia que seu sistema precisa cobrir pode ajudar, pois alguns intervalos são restritos para uso em países específicos. Por exemplo, os intervalos 62 incluem alguns subintervalos AAA nos EUA, mas se sua base de comerciantes estiver fora dos EUA, você poderá tratar todos os 62 como UnionPay.
Você também pode ser solicitado a tratar um cartão de maneira diferente, com base na localização do comerciante. Por exemplo, tratar certos cartões do Reino Unido como débito no mercado interno, mas como crédito internacional.

Há um conjunto de regras muito útil mantido por um grande banco adquirente. Por exemplo https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf e https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf . (Links válidos a partir de junho de 2017, graças ao usuário que forneceu um link para a referência atualizada.) Mas lembre-se de que, embora essas regras de CRR possam representar o universo de emissão de cartões, como se aplica aos comerciantes adquiridos por essa entidade, não inclui, por exemplo, intervalos identificados como CUP / UPI.

Esses comentários se aplicam aos cenários de tarja magnética (MagStripe) ou PKE (Pan Key Entry). A situação é diferente novamente no mundo da ICC / EMV.

Atualização: Outras respostas nesta página (e também na página vinculada da WikiPedia) têm o JCB como sempre com 16 anos. No entanto, em minha empresa, temos uma equipe dedicada de engenheiros que certificam nossos dispositivos e softwares de PDV em vários bancos e regiões geográficas adquirentes. O mais recente pacote de cartões de certificação que essa equipe tem do JCB, teve um caso de aprovação por um PAN de 19 anos.

MikeRoger
fonte
Olá @CaiqueOliveira, consulte os links atualizados. Agradecimentos a mac9416, que forneceu um link para a referência atualizada das Regras do BIN.
MikeRoger
1
Obrigado @ mac9416, pela referência atualizada das Regras do BIN.
MikeRoger
5

Swift 2.1 Versão da resposta de Usman Y. Use uma instrução print para verificar a chamada por algum valor de string

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 ""

}
Daisy R.
fonte
4

O Stripe forneceu esta fantástica biblioteca javascript para detecção de esquema de cartões. Deixe-me adicionar alguns trechos de código e mostrar como usá-lo.

Em primeiro lugar, inclua-o na sua página da web como

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

Em segundo lugar, use a função cardType para detectar o esquema do cartão.

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

Aqui estão os links de referência para mais exemplos e demonstrações.

  1. Blog de distribuição de jquery.payment.js
  2. Repositório do Github
NJInamdar
fonte
4

No Swift, você pode criar uma enumeração para detectar o tipo de cartão de crédito.

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

Chame o método CreditCardType.cardTypeForCreditCardNumber ("# card number") que retorna o valor da enumeração CreditCardType.

Vidyalaxmi
fonte
3

Minha solução com 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;
}

No caso de retorno de 0, o tipo de cartão de crédito não é detectado.

A classe "creditcard" deve ser adicionada ao campo de entrada do cartão de crédito.

ZurabWeb
fonte
1
Variação das respostas existentes.
Gajus
1
Sim, eu usei o código das respostas acima, melhorei e publiquei aqui. Obrigado pela downvote ...
ZurabWeb
3
Você deve (a) sugerir isso como uma melhoria no código existente, (b) escrever as contribuições apropriadas ou (c) fazer referência às fontes que você usou para escrever as expressões regulares.
Gajus 8/08/2014
1
Gajus, acredito que ajudei a comunidade da maneira que pude naquele momento. Por favor, pare de me dizer que deveria ter feito algo por alguém. Fiz o que pensei que poderia ter sido útil.
precisa saber é o seguinte
3

Pesquisei bastante um pouco sobre formatação de cartão de crédito e formatação de números de telefone. Encontrei muitas dicas boas, mas nada realmente atendia aos meus desejos exatos, por isso criei esse código . Você o usa assim:

var sf = smartForm.formatCC(myInputString);
var cardType = sf.cardType;
ShadeTreeDeveloper
fonte
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
       },
Parvez
fonte
A questão é sobre o algoritmo para verificar um cartão de crédito, não uma implementação específica. O que faz este código?
Emil Vikström
2

Apenas uma pequena colher de alimentação:

$("#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");

        }

    });
Pitada
fonte
2

Aqui está um exemplo de algumas funções booleanas escritas em Python que retornam Truese o cartão for detectado conforme o nome da função.

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
Radtek
fonte
1

Os seis primeiros dígitos de um número de cartão (incluindo o dígito MII inicial) são conhecidos como número de identificação do emissor (IIN). Eles identificam a instituição emissora do cartão que emitiu o cartão para o titular do cartão. O restante do número é alocado pelo emissor do cartão. O comprimento do número do cartão é o número de dígitos. Muitos emissores de cartões imprimem o número completo da conta e do IIN no cartão.

Com base nos fatos acima, eu gostaria de manter um trecho de código JAVA para identificar a marca do cartão.

Tipos de cartão de amostra

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

Prefixos de cartões

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

Verifique se o número de entrada possui algum dos prefixos fornecidos.

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

Finalmente, o método 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;
}

Referência

Anoop M
fonte
1

Tente isso para kotlin. Adicione Regex e adicione à instrução 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"
        }
    }
OhhhThatVarun
fonte
0

As regras de expressão regular que correspondem aos respectivos fornecedores de cartões :

  • (4\d{12}(?:\d{3})?) para VISA.
  • (5[1-5]\d{14}) para MasterCard.
  • (3[47]\d{13}) para AMEX.
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) para o Maestro.
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) para Diners Club.
  • (6(?:011|5[0-9]{2})[0-9]{12}) para o Discover.
  • (35[2-8][89]\d\d\d{10}) para JCB.
rajan
fonte
Eu acho que o regex para JCB está incorreto. Todos os quatro primeiros dígitos entre 3528 e 3589 devem ser aceitos, mas 3570 não é, por exemplo.
Gabe
0

Eu uso https://github.com/bendrucker/creditcards-types/ para detectar o número do cartão de crédito. Um problema que encontrei é descobrir o número de teste 6011 1111 1111 1117

em https://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/ , podemos ver que é um número de descoberta porque começa em 6011. Mas o resultado obtido pelos tipos de cartões de crédito é "Maestro". Abri a questão ao autor. Ele me respondeu muito em breve e fornece este documento em PDF https://www.discovernetwork.com/downloads/IPP_VAR_Compliance.pdf A partir do documento, podemos ver claramente que 6011 1111 1111 1117 não se enquadra no intervalo do cartão de crédito Discover.

yuxiaomin
fonte
Estou tendo o mesmo problema, você resolveu isso?
Lucasvm1980
@ lucasvm1980 Acho que o arquivo pdf discovernetwork.com é mais confiável. E o número 6011 1111 1111 1117 é apenas um número de teste, nenhum cartão de crédito real tem esse número. Então eu acho que não precisa se preocupar com isso.
precisa
Parece que há algum bug com algum cartão Discover, tentei um número válido e também recebi esse erro.
Lucasvm1980
@ lucasvm1980 você pode fornecer o número e enviar um problema no github?
yuxiaomin
0

Experimente isso.

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
}

Usar.

if (self.checkCardValidation(number: "yourNumber") == true) {
     print("Card Number valid")
}else{
     print("Card Number not valid")
}
Dixit Akabari
fonte
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) {

            }
        });
gaurav gupta
fonte