¿Cómo se detecta el tipo de tarjeta de crédito en función del número?

516

Estoy tratando de descubrir cómo detectar el tipo de tarjeta de crédito basándose únicamente en su número. ¿Alguien sabe de una manera definitiva y confiable de encontrar esto?

Andrew Edvalson
fuente
3
Usando una expresión regular. Mira este enlace para más información.
senfo
3
Los detalles están todos en Wikipedia: en.wikipedia.org/wiki/Credit_card_numbers
Sten Vesterli
1
Hay una buena tabla resumen en Wikipedia, en en.wikipedia.org/wiki/Credit_card_numbers . Son los primeros uno a seis dígitos que indican el tipo y el emisor de la tarjeta.
Alex
3
No usaría una expresión regular que no sea para extraer el primer grupo numérico, generalmente se puede distinguir solo de los primeros 4 números (en los EE. UU.). Además, antes de molestarse en pagar la compensación de un cargo, ejecute una suma de verificación Mod 10 en el número de tarjeta para asegurarse de que pueda ser legítimo. Algoritmo de Luhn
Dan Blair
3
También puede alguien comentar si estos algoritmos son buenos "para siempre", o cambian periódicamente, como por ejemplo el algoritmo para "calcular si un número de teléfono está en California"
Simon_Weaver

Respuestas:

772

El número de tarjeta de crédito / débito se conoce como PAN o Número de cuenta principal . Los primeros seis dígitos del PAN se toman del IIN , o número de identificación del emisor , perteneciente al banco emisor (los IIN se conocían anteriormente como BIN - Números de identificación bancaria - por lo que puede ver referencias a esa terminología en algunos documentos). Estos seis dígitos están sujetos a un estándar internacional, ISO / IEC 7812 , y se pueden usar para determinar el tipo de tarjeta a partir del número.

Desafortunadamente, la base de datos ISO / IEC 7812 actual no está disponible públicamente, sin embargo, hay listas no oficiales, tanto comerciales como gratuitas, incluso en Wikipedia .

De todos modos, para detectar el tipo del número, puede usar una expresión regular como las siguientes: Crédito por expresiones originales

Visa: ^4[0-9]{6,}$ los números de tarjeta Visa comienzan con un 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, los números de MasterCard comienzan con los números 51 a 55, pero esto solo detectará las tarjetas de crédito MasterCard ; Hay otras tarjetas emitidas con el sistema MasterCard que no entran en este rango IIN. En 2016, agregarán números en el rango (222100-272099).

American Express: ^3[47][0-9]{5,}$ los números de tarjeta American Express comienzan con 34 o 37.

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ los números de tarjeta Diners Club comienzan con 300 a 305, 36 o 38. Hay tarjetas Diners Club que comienzan con 5 y tienen 16 dígitos. Se trata de una empresa conjunta entre Diners Club y MasterCard y debe procesarse como una MasterCard.

Discover: ^6(?:011|5[0-9]{2})[0-9]{3,}$ los números de tarjetas Discover comienzan con 6011 o 65.

JCB: las ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ tarjetas JCB comienzan con 2131, 1800 o 35.

Desafortunadamente, hay varios tipos de tarjetas procesadas con el sistema MasterCard que no viven en el rango IIN de MasterCard (números que comienzan 51 ... 55); El caso más importante es el de las tarjetas Maestro, muchas de las cuales han sido emitidas desde los rangos IIN de otros bancos y, por lo tanto, se encuentran en todo el espacio numérico. Como resultado, puede ser mejor suponer que cualquier tarjeta que no sea de otro tipo que acepte debe ser una MasterCard .

Importante : los números de tarjeta varían en longitud; por ejemplo, Visa emitió en el pasado tarjetas con PAN de 13 dígitos y tarjetas con PAN de 16 dígitos. La documentación de Visa actualmente indica que puede emitir o puede haber emitido números con entre 12 y 19 dígitos. Por lo tanto, no debe verificar la longitud del número de tarjeta, excepto para verificar que tenga al menos 7 dígitos (para un IIN completo más un dígito de verificación, que debe coincidir con el valor predicho por el algoritmo de Luhn ).

Una pista más: antes de procesar un PAN del titular de la tarjeta, elimine cualquier espacio en blanco y caracteres de puntuación de la entrada . ¿Por qué? Debido a que generalmente es mucho más fácil ingresar los dígitos en grupos, de forma similar a cómo se muestran en el frente de una tarjeta de crédito real, es decir

4444 4444 4444 4444

es mucho más fácil ingresar correctamente que

4444444444444444

Realmente no hay ningún beneficio en castigar al usuario porque ha ingresado caracteres que no espera aquí.

Esto también implica asegurarse de que los campos de entrada tengan espacio para al menos 24 caracteres; de lo contrario, los usuarios que ingresen espacios se quedarán sin espacio. Recomiendo que amplíe el campo lo suficiente como para mostrar 32 caracteres y permita hasta 64; eso le da mucho espacio para la expansión.

Aquí hay una imagen que da un poco más de información:

ACTUALIZACIÓN (2014): el método de suma de verificación ya no parece ser una forma válida de verificar la autenticidad de una tarjeta como se señala en los comentarios sobre esta respuesta.

ACTUALIZACIÓN (2016): Mastercard implementará nuevos rangos BIN a partir de Ach Payment .

Verificación de tarjeta de crédito

senfo
fuente
77
gran ejemplo ¿tienes la expresión regular para las tarjetas maestro?
Manikandan
44
No no no. No puede confiar en la longitud de los números de tarjeta; Pueden cambiar en cualquier momento. La única parte del número de tarjeta en la que puede confiar es el IIN (que solía llamarse BIN) y que es un prefijo del número. Además, no puede detectar las tarjetas Mastercard de la manera que sugiere; eso solo recogerá un subconjunto de las tarjetas que se procesan a través del sistema Mastercard (el principal problema son las tarjetas Maestro, que tienen una variedad de prefijos IIN).
alastair
2
@alastair, ¿leíste las expresiones antes de comentar? Fueron escritos específicamente para usar el IIN, así que no entiendo lo que estás tratando de decir. Además, el IIN se puede utilizar para identificar al emisor de la tarjeta, pero no validarlo. 5412, por ejemplo, no representa una MasterCard completa, pero su sugerencia implicaría que sí. No he encontrado ninguna prueba de que las MasterCards no sean más que 16 dígitos. No dude en proporcionar una fuente para su reclamo. Sin embargo, tiene razón al mencionar que es necesario realizar una actualización para las tarjetas Maestro.
senfo
3
@senfo Tienes razón, 5412 no sería un número completo de Mastercard. Los IIN tienen seis dígitos, por lo que un número de tarjeta completo debe tener 7 dígitos (mínimo) y debe pasar el cheque Luhn. No hay necesidad de "prueba" de que los números de Mastercard tengan más de 16 dígitos; El punto es que, independientemente de la situación actual, en el futuro podrían emitir tarjetas con 17 o 18 dígitos, o incluso algunas con 15. Confiar en que tengan 16 dígitos es innecesario y crea un riesgo de mantenimiento a largo plazo.
alastair
3
Me resulta muy difícil creer que algunas tarjetas válidas no tengan un dígito de verificación correcto de acuerdo con el algoritmo de Luhn. Se usó absolutamente en todas partes para verificar los números de tarjetas contra errores tipográficos simples e intentos de fraude tontos. En cambio, he observado que algunas personas bastante inteligentes simplemente no comprenden el algoritmo, y simplemente lo calculan mal.
Rennex
74

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

Prueba de unidad:

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
fuente
1
@ jolly.exe: su violín regresa indefinido para todas las pruebas. No funciona :(
ShadeTreeDeveloper
@ShadeTreeDeveloper simplemente ingrese cualquier valor, por ejemplo. 372176090165471 para AMAX en campo de texto
Code Spy
@ jolly.exe Ya veo ... esperaba algo que se formatee a medida que escribo (fuera del evento keyup). El violín funciona cuando ingreso un número completo.
ShadeTreeDeveloper
Terminé escribiendo este bit de código para hacer el formato de entrada y la validación que quería. quercusv.github.io/smartForm
ShadeTreeDeveloper
¿Sabes cómo detectar los números de tarjeta v-pay y bancontact? Gracias
Oleksandr IY
38

Actualizado: 15 de junio de 2016 (como una solución definitiva actualmente)

Tenga en cuenta que incluso doy mi voto para que el que está más votado, pero para dejar en claro que estos son los regexps que realmente funcionan, lo probé con miles de códigos BIN reales. ¡Lo más importante es usar cadenas de inicio (^) de lo contrario, dará resultados falsos en el mundo real!

JCB ^(?:2131|1800|35)[0-9]{0,}$ Comience con: 2131, 1800, 35 (3528-3589)

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

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

Visa ^4[0-9]{0,}$ comienza con: 4

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

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro siempre crece en el rango: 60-69 , comenzó con / no con otra cosa, pero el inicio 5 debe codificarse como tarjeta maestra de todos modos. Las tarjetas Maestro deben detectarse al final del código porque algunas otras tienen un rango de 60-69. Por favor mira el código.

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

En javascript utilizo esta función. Esto es bueno cuando lo asigna a un evento onkeyup y da resultado tan pronto como sea posible.

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

Aquí puedes jugar con él:

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

Para PHP, use esta función, esto también detecta algunas tarjetas 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
fuente
1
Y tenga en cuenta que esto es solo detección de número CC y no validación. Eso está separado, debería ser un cheque de Luhn ...
Janos Szabo
¿Dónde está Visa Electron, y por qué el maestro cheque devuelve MasterCard en algunos casos? ¿No debería la MasterCard verificar eso por sí misma?
BadHorsie
No reconoce este número de prueba JCB como ninguno de los tipos (3088514174175777) e identifica este número JCB de prueba como diners_club (3096278649822922). Asumiendo que esta lista de números de tarjeta de prueba es válida de todos modos ( freeformatter.com/credit-card-number-generator-validator.html )
Drew
no hay documentación que indique que comenzar 308 o 309 podría ser una tarjeta JCB
Janos Szabo
+1 para proporcionar código de detección de tipo cc, que es lo que normalmente desea hacer para el ux: la expresión regular para el nuevo rango en MC necesita un pequeño truco: / ^ (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";
}

Aquí está la función para verificar el tipo de tarjeta de crédito usando Regex, c #

Usman Younas
fuente
19

Mira esto:

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
fuente
15

Hace poco necesitaba esa funcionalidad, estaba transfiriendo el Validador de tarjetas de crédito de Zend Framework a Ruby. gema de rubí: https://github.com/Fivell/credit_card_validations zend framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

Ambos usan rangos INN para detectar el tipo. Aquí puedes leer sobre INN

De acuerdo con esto, puede detectar la tarjeta de crédito alternativamente (sin expresiones regulares, pero declarando algunas reglas sobre prefijos y posible longitud)

Entonces tenemos las siguientes reglas para la mayoría de las tarjetas usadas

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

}

Luego, al buscar el prefijo y comparar la longitud, puede detectar la marca de la tarjeta de crédito. Tampoco te olvides del algoritmo de Luhn (se describe aquí http://en.wikipedia.org/wiki/Luhn ).

ACTUALIZAR

La lista actualizada de reglas se puede encontrar aquí https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml

Fivell
fuente
2
Muy ilustrativo Las tarjetas VISA pueden tener 13 dígitos.
Herman Kan
@HermanKan, ningún sitio web de VISA dice que debería tener una longitud de 16, creo que hace mucho tiempo podría ser 13, pero no hoy en día
Fivell
1
Creo que es soporte heredado
Fivell
1
@HermanKan, hay una cosa más, VISA tiene tarjetas VPay y de acuerdo con Wikipedia, la marca VPay de Visa puede especificar longitudes PAN de 13 a 19 dígitos, por lo que ahora se está viendo un número de tarjeta de más de 16 dígitos.
Fivell
1
@ Ethan, verifique el último enlace en mi respuesta actualizada raw.githubusercontent.com/Fivell/credit_card_validations/master/…
Fivell
13

Aquí está el código completo C # o VB para todo tipo de cosas relacionadas con CC en codeproject.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PasesLuhnTest

Este artículo ha estado publicado durante un par de años sin comentarios negativos.

Simon_Weaver
fuente
1
@barett - lo arregló. parece que lo movieron de la categoría 'aspnet' a la categoría 'validación' que cambió el enlace
Simon_Weaver
2
El enlace está roto. Tal vez esta es la misma utilidad? codeproject.com/Articles/20271/…
Josh Noe
Ese código de proyecto de código es de 2007. Advertencia, puede estar desactualizado.
aron
8

Versión 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;
            }
        }
    };
Mella
fuente
8

La respuesta de Anatoliy en 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
fuente
7

Aquí hay una función de clase php que devuelve CCtype por CCnumber.
Este código no valida la tarjeta o no ejecuta el algoritmo de Luhn, solo trata de encontrar el tipo de tarjeta de crédito según la tabla de esta página . utiliza básicamente la longitud de CCnumber y el prefijo de CCcard para determinar el 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
fuente
6

No intente detectar el tipo de tarjeta de crédito como parte del procesamiento de un pago. Corre el riesgo de rechazar transacciones válidas.

Si necesita proporcionar información a su procesador de pagos (p. Ej., El objeto de la tarjeta de crédito de PayPal requiere nombrar el tipo de tarjeta ), adivine con la menor información disponible, p. Ej.

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

Esta implementación (usando solo los primeros dos dígitos) es suficiente para identificar todos los esquemas de tarjetas principales (y en el caso de PayPal, todos los compatibles). De hecho, es posible que desee omitir la excepción por completo y usar el tipo de tarjeta más popular. Deje que la pasarela de pago / procesador le diga si hay un error de validación en respuesta a su solicitud.

La realidad es que su pasarela de pago no se preocupa por el valor que proporciona .

Gajus
fuente
1
Esto es simplemente falso. Sé de 3 proveedores diferentes que sí requieren que se pasen los tipos de tarjeta, y si no lo pasa, la transacción fallará.
Ed DeGagne
3
@EdDeGagne - "no le importa qué valor" no es lo mismo que "no le importa si se pasa".
Quentin Skousen
¿Dónde especifiqué tampoco? Simplemente mencioné que hay proveedores en uso que requieren que USTED pase el tipo CC, nada más.
Ed DeGagne
no puede simplificar este problema complejo, pero generalmente los proveedores de pago no requieren que sugiera el tipo de tarjeta, tienen su propio método para detectarlo
Janos Szabo
6

Los primeros números de la tarjeta de crédito pueden usarse para aproximarse al vendedor:

  • Visa: 49,44 o 47
  • Visa electron: 42, 45, 48, 49
  • MasterCard: 51
  • Amex: 34
  • Comensales: 30, 36, 38
  • JCB: 35
Shoban
fuente
Estos rangos se han actualizado principalmente, las compañías de proveedores de tarjetas han agregado muchos más rangos que los mencionados en la publicación.
NJInamdar
6

En el reconocimiento de rango de tarjeta (CRR), un inconveniente con los algoritmos que utilizan una serie de expresiones regulares u otros rangos codificados, es que los BIN / IIN cambian con el tiempo en mi experiencia. La marca compartida de tarjetas es una complicación continua. Los diferentes adquirentes / comerciantes de tarjetas pueden necesitar que trate la misma tarjeta de manera diferente, dependiendo, por ejemplo, de la geolocalización.

Además, en los últimos años, por ejemplo, con tarjetas UnionPay en circulación más amplia, los modelos existentes no hacen frente a nuevos rangos que a veces se entrelazan con rangos más amplios que reemplazan.
Puede ser útil conocer la geografía que necesita cubrir su sistema, ya que algunos rangos están restringidos para su uso en determinados países. Por ejemplo, los rangos 62 incluyen algunos subrangos AAA en los EE. UU., Pero si su base comercial está fuera de los EE. UU., Puede tratar a los 62 como UnionPay.
También se le puede pedir que trate una tarjeta de manera diferente según la ubicación del comerciante. Por ejemplo, para tratar ciertas tarjetas del Reino Unido como débito a nivel nacional, pero como crédito internacional.

Hay un conjunto muy útil de reglas mantenidas por un banco adquirente importante. Por ejemplo, https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf y https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf . (Vínculos válidos a partir de junio de 2017, gracias al usuario que proporcionó un vínculo a la referencia actualizada). Pero tenga en cuenta la advertencia de que, si bien estas reglas de CRR pueden representar el universo de Emisión de tarjetas tal como se aplica a los comerciantes adquiridos por esa entidad, no incluye, por ejemplo, rangos identificados como CUP / UPI.

Estos comentarios se aplican a escenarios de banda magnética (MagStripe) o PKE (Entrada de clave de desplazamiento). La situación es diferente nuevamente en el mundo de ICC / EMV.

Actualización: Otras respuestas en esta página (y también la página de WikiPedia vinculada) tienen JCB como siempre 16 de largo. Sin embargo, en mi empresa tenemos un equipo dedicado de ingenieros que certifican nuestros dispositivos y software POS en múltiples bancos y geografías adquirientes. El paquete de tarjetas de certificación más reciente que este equipo tiene de JCB, tenía un caso de pase para un PAN de 19 largos.

MikeRoger
fuente
Hola @CaiqueOliveira, ver enlaces actualizados. Gracias a mac9416 que proporcionó un enlace a la referencia actualizada de las Reglas BIN.
MikeRoger
1
Gracias @ mac9416, por la referencia actualizada de las Reglas BIN.
MikeRoger
5

Versión Swift 2.1 de la respuesta de Usman Y. Use una declaración de impresión para verificar, así que llame por algún valor de cadena

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.
fuente
4

Stripe ha proporcionado esta fantástica biblioteca de JavaScript para la detección de esquemas de tarjetas. Permítame agregar algunos fragmentos de código y mostrarle cómo usarlo.

En primer lugar inclúyalo a su página web como

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

En segundo lugar, use la función cardType para detectar el esquema de la tarjeta.

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

Aquí están los enlaces de referencia para más ejemplos y demostraciones.

  1. Blog de stripe para jquery.payment.js
  2. Repositorio de Github
NJInamdar
fuente
4

En Swift puede crear una enumeración para detectar el tipo de tarjeta 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
  }
}

Llame al método CreditCardType.cardTypeForCreditCardNumber ("# número de tarjeta") que devuelve el valor de enumeración CreditCardType.

Vidyalaxmi
fuente
3

Mi solución con 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;
}

En caso de que se devuelva 0, el tipo de tarjeta de crédito no se detecta.

La clase "tarjeta de crédito" debe agregarse al campo de entrada de la tarjeta de crédito.

ZurabWeb
fuente
1
Variación de respuestas existentes.
Gajus
1
Sí, utilicé el código de las respuestas anteriores, MEJORÉ y lo publiqué aquí. Gracias por el
voto negativo
3
Debería haber (a) sugerido esto como una mejora del código existente, (b) escribir las contribuciones apropiadas, o (c) hacer referencia a las fuentes que ha utilizado para escribir las expresiones regulares.
Gajus
1
Gajus, creo que ayudé a la comunidad de la manera que pude en ese momento, por favor, deja de decirme que debería haber hecho algo por alguien. Hice lo que pensé que podría haber sido útil.
ZurabWeb
3

Busqué bastante por el formato de la tarjeta de crédito y el formato del número de teléfono. Encontré muchos buenos consejos, pero nada realmente se ajustaba a mis deseos exactos, así que creé este bit de código . Lo usas así:

var sf = smartForm.formatCC(myInputString);
var cardType = sf.cardType;
ShadeTreeDeveloper
fuente
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
fuente
La pregunta es sobre el algoritmo para verificar una tarjeta de crédito, no una implementación específica. ¿Qué hace este código?
Emil Vikström
2

Solo una cucharadita de alimentación:

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

        }

    });
Pellizco
fuente
2

Aquí hay un ejemplo de algunas funciones booleanas escritas en Python que regresan Truesi la tarjeta se detecta según el nombre de la función.

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
fuente
1

Los primeros seis dígitos de un número de tarjeta (incluido el dígito MII inicial) se conocen como el número de identificación del emisor (IIN). Estos identifican la institución emisora ​​de la tarjeta que emitió la tarjeta al titular de la tarjeta. El resto del número lo asigna el emisor de la tarjeta. La longitud del número de tarjeta es su número de dígitos. Muchos emisores de tarjetas imprimen el IIN completo y el número de cuenta en su tarjeta.

En base a los hechos anteriores, me gustaría mantener un fragmento de código JAVA para identificar la marca de la tarjeta.

Tipos de tarjeta de muestra

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

Prefijos de tarjeta

// 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 si el número de entrada tiene alguno de los prefijos dados.

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, el método de utilidad

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

Referencia

Anoop M
fuente
1

Prueba esto para kotlin. Agregue Regex y agregue a la instrucción 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"
        }
    }
Ohhh, eso Varun
fuente
0

Las reglas de expresión regular que coinciden con los proveedores de tarjetas respectivos :

  • (4\d{12}(?:\d{3})?) para la visa.
  • (5[1-5]\d{14}) para MasterCard.
  • (3[47]\d{13}) para AMEX
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) para maestro.
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) para Diners Club.
  • (6(?:011|5[0-9]{2})[0-9]{12}) para descubrir.
  • (35[2-8][89]\d\d\d{10}) para JCB
rajan
fuente
Creo que regex para JCB es incorrecto. Deben aceptarse los primeros cuatro dígitos entre 3528 y 3589, pero 3570 no, por ejemplo.
Gabe
0

Utilizo https://github.com/bendrucker/creditcards-types/ para detectar el tipo de tarjeta de crédito del número. Un problema que encontré es descubrir el número de prueba 6011 1111 1111 1117

de https://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/ podemos ver que es un número de descubrimiento porque comienza en 6011. Pero el resultado que obtengo de los tipos de tarjetas de crédito es "Maestro". Abrí el tema al autor. Él me respondió muy pronto y proporcionó este documento en pdf https://www.discovernetwork.com/downloads/IPP_VAR_Compliance.pdf. Desde el documento podemos ver claramente que 6011 1111 1111 1117 no se encuentra dentro del rango de descubrir tarjetas de crédito.

yuxiaomin
fuente
Estoy teniendo el mismo problema, ¿resolvió esto?
lucasvm1980
@ lucasvm1980 Creo que el archivo pdf discovernetwork.com es más confiable. Y el número 6011 1111 1111 1117 es solo un número de prueba, ninguna tarjeta de crédito real tiene este número. Así que creo que no hay que preocuparse por esto.
yuxiaomin
Parece que hay algún error con alguna tarjeta Discover, he intentado un número válido y también obtengo ese error.
lucasvm1980
@ lucasvm1980 ¿puede proporcionar el número y enviar un problema en github?
yuxiaomin
0

Intenta esto. Para rápido.

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
}

Utilizar.

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