Jak rozpoznać typ karty kredytowej na podstawie numeru?


516

Próbuję dowiedzieć się, jak wykryć rodzaj karty kredytowej na podstawie wyłącznie jej liczby. Czy ktoś zna ostateczny i niezawodny sposób na znalezienie tego?


3
Używając wyrażenia regularnego. Sprawdź ten link, aby uzyskać więcej informacji.
senfo

3
Wszystkie szczegóły są na Wikipedii: en.wikipedia.org/wiki/Credit_card_numbers
Sten Vesterli

1
W Wikipedii znajduje się dobra tabela podsumowań na stronie en.wikipedia.org/wiki/Credit_card_numbers . Jest to pierwsza cyfra składająca się z sześciu cyfr, określająca typ i wystawcę karty.
Alex

3
Nie użyłbym wyrażenia regularnego innego niż wyciągnięcie pierwszej grupy liczbowej, ogólnie można powiedzieć po pierwszych 4 liczbach (w USA). Również przed zadaniem sobie trudu zapłaty za wyczyszczenie opłaty uruchom sumę kontrolną Mod 10 na numerze karty, aby upewnić się, że może być uzasadniona. Algorytm Luhna
Dan Blair

3
może również komentować, czy te algorytmy są dobre „na zawsze” - czy zmieniają się okresowo, jak na przykład algorytm „obliczania, czy numer telefonu jest w Kalifornii”
Simon_Weaver

Odpowiedzi:


771

Numer karty kredytowej / debetowej jest określany jako PAN lub główny numer konta . Pierwsze sześć cyfr PAN pochodzi z numeru IIN lub numeru identyfikacyjnego emitenta należącego do banku wydającego (numery IIN były wcześniej znane jako BIN - bankowe numery identyfikacyjne - dlatego w niektórych dokumentach można znaleźć odniesienia do tej terminologii). Te sześć cyfr podlega międzynarodowej normie ISO / IEC 7812 i można ich użyć do określenia rodzaju karty na podstawie numeru.

Niestety rzeczywista baza danych ISO / IEC 7812 nie jest publicznie dostępna, jednak istnieją nieoficjalne listy, zarówno komercyjne, jak i bezpłatne, w tym na Wikipedii .

W każdym razie, aby wykryć typ na podstawie liczby, możesz użyć wyrażenia regularnego, takiego jak poniższe: Kredyt za oryginalne wyrażenia

Visa: ^4[0-9]{6,}$ Numery kart Visa zaczynają się od 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,}$ Przed 2016 r. Numery MasterCard zaczynają się od cyfr 51 do 55, ale wykrywa to tylko karty kredytowe MasterCard ; istnieją inne karty wydane przy użyciu systemu MasterCard, które nie należą do tego zakresu IIN. W 2016 r. Dodadzą liczby z zakresu (222100–272099).

American Express: ^3[47][0-9]{5,}$ Numery kart American Express zaczynają się od 34 lub 37.

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ Numery kart Diners Club zaczynają się od 300 do 305, 36 lub 38. Istnieją karty Diners Club, które zaczynają się od 5 i mają 16 cyfr. Są to wspólne przedsięwzięcia Diners Club i MasterCard i powinny być przetwarzane jak karta MasterCard.

Odkryj: ^6(?:011|5[0-9]{2})[0-9]{3,}$ numery kart zaczynają się od 6011 lub 65.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ Karty JCB zaczynają się od 2131, 1800 lub 35.

Niestety istnieje wiele rodzajów kart przetwarzanych w systemie MasterCard, które nie działają w zakresie IIN MasterCard (numery zaczynające się od 51 ... 55); najważniejszym przypadkiem są karty Maestro, z których wiele zostało wydanych z zakresów IIN innych banków, a więc są rozmieszczone na całej przestrzeni liczbowej. W związku z tym najlepiej założyć, że każda karta, która nie jest innego rodzaju, który akceptujesz, musi być kartą MasterCard .

Ważne : numery kart różnią się długością; na przykład Visa wydawała w przeszłości karty z 13 cyfrowymi PAN i karty z 16 cyfrowymi PAN. Dokumentacja Visa obecnie wskazuje, że może wydawać lub wydawać numery od 12 do 19 cyfr. Dlatego nie należy sprawdzać długości numeru karty, poza sprawdzeniem, czy ma on co najmniej 7 cyfr (dla pełnego IIN plus jedna cyfra kontrolna, które powinny być zgodne z wartością przewidywaną przez algorytm Luhna ).

Jeszcze jedna wskazówka: przed przetworzeniem PAN karty posiadacza karty, usuń wszelkie białe znaki i znaki interpunkcyjne z wejścia . Dlaczego? Ponieważ zwykle o wiele łatwiej jest wprowadzać cyfry w grupach, podobnie jak są wyświetlane na przedniej stronie rzeczywistej karty kredytowej, tj

4444 4444 4444 4444

jest znacznie łatwiej wprowadzić poprawnie niż

4444444444444444

Naprawdę nie ma korzyści z karania użytkownika, ponieważ wprowadzili oni znaki, których się tu nie spodziewasz.

Oznacza to również upewnienie się, że w polach wejściowych jest miejsce na co najmniej 24 znaki, w przeciwnym razie użytkownikom, którzy wejdą w spacje, zabraknie miejsca. Zalecam, aby pole było wystarczająco szerokie, aby wyświetlało 32 znaki i pozwalało na użycie maksymalnie 64 znaków; daje to dużo miejsca na rozbudowę.

Oto obraz, który daje nieco więcej wglądu:

AKTUALIZACJA (2014): Metoda sumy kontrolnej nie wydaje się już prawidłowym sposobem weryfikacji autentyczności karty, jak zauważono w komentarzach do tej odpowiedzi.

AKTUALIZACJA (2016): Mastercard wdroży nowe zakresy BIN od Ach Payment .

Weryfikacja karty kredytowej


7
świetny przykład. czy masz wyrażenie regularne dla kart Maestro?
Manikandan

4
Nie nie nie. Nie możesz polegać na długości numerów kart; mogą zmienić w dowolnym momencie. Jedyną częścią numeru karty, na której można polegać, jest numer IIN (wcześniej nazywany BIN), który jest prefiksem numeru. Ponadto nie można wykryć kart Mastercard w sposób sugerowany przez użytkownika; który odbierze tylko podzbiór kart przetwarzanych przez system Mastercard (głównym problemem są karty Maestro, które mają różne prefiksy IIN).
alastair

2
@alastair czytałeś wyrażenia przed komentowaniem? Zostały napisane specjalnie z myślą o korzystaniu z IIN, więc nie rozumiem, co próbujesz powiedzieć. Ponadto numeru IIN można użyć do identyfikacji wydawcy karty, ale nie można go zweryfikować. Na przykład 5412 nie reprezentuje pełnej karty MasterCard, ale twoja sugestia sugerowałaby, że tak. Nie znalazłem żadnego dowodu na to, że MasterCard to tylko 16 cyfr. Podaj źródło roszczenia. Masz jednak rację, wspominając, że należy dokonać aktualizacji kart Maestro.
senfo

3
@senfo Masz rację, 5412 nie byłby pełnym numerem Mastercard. Numery IIN mają sześć cyfr, więc pełny numer karty musi składać się z 7 cyfr (minimum) i musi przejść test Luhna. Nie ma potrzeby „potwierdzania”, że numery Mastercard mają cokolwiek innego niż 16 cyfr; Chodzi o to, że niezależnie od dzisiejszej sytuacji, w przyszłości mogą wydawać karty z 17 lub 18 cyframi, a w tym niektóre z 15 cyframi. Poleganie na nich, że mają 16 cyfr, jest niepotrzebne i stwarza ryzyko długoterminowej konserwacji.
alastair

3
Bardzo trudno mi uwierzyć, że niektóre prawidłowe karty nie miałyby prawidłowej cyfry kontrolnej zgodnie z algorytmem Luhna. Używał absolutnie wszędzie, aby sprawdzać numery kart pod kątem prostych literówek i głupich prób oszustwa. Zamiast tego zaobserwowałem, że niektórzy całkiem sprytni ludzie po prostu nie rozumieją algorytmu i po prostu źle go obliczają.
Rennex,

74

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

Test jednostkowy:

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

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

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

            '5019000000000000': 'DANKORT',

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

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

            '6360000000000000': 'INTERPAYMENT',

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

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

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

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

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

1
@ jolly.exe - Twoje skrzypce wracają niezdefiniowane dla wszystkich testów. Nie działa :(
ShadeTreeDeveloper

@ShadeTreeDeveloper wystarczy wpisać dowolną wartość, np. 372176090165471 dla AMAX w polu tekstowym
Code Spy

@ jolly.exe Rozumiem ... Miałem nadzieję, że coś sformatuje się podczas pisania (poza zdarzeniem keyup). Skrzypce działa, gdy wprowadzę pełny numer.
ShadeTreeDeveloper

Skończyło się na tym, że napisałem ten fragment kodu, aby przeprowadzić formatowanie i sprawdzanie poprawności, które chciałem. quercusv.github.io/smartForm
ShadeTreeDeveloper

Czy wiesz, jak wykryć numery kart V-Pay i Bancontact? Dzięki
Oleksandr IY

38

Zaktualizowano: 15 czerwca 2016 r. (Jako obecnie najlepsze rozwiązanie)

Pamiętaj, że nawet oddaję głos na ten, który jest najczęściej głosowany, ale aby wyjaśnić, że tak naprawdę wyrażenia regularne działają, przetestowałem go z tysiącami prawdziwych kodów BIN. Najważniejsze jest użycie ciągów początkowych (^), w przeciwnym razie da to fałszywe wyniki w prawdziwym świecie!

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

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

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

Visa ^4[0-9]{0,}$ Zacznij od: 4

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

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro zawsze rośnie w przedziale: 60-69 , zaczynał od / nie czegoś innego, ale start 5 musi być zakodowany jako mastercard. Karty Maestro muszą zostać wykryte na końcu kodu, ponieważ niektóre inne mają zakres od 60 do 69. Proszę spojrzeć na kod.

Odkryć ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ Odkryj dość trudny do kodowania, zacznij od: 6011, 622126-622925, 644-649, 65

W javascript używam tej funkcji. Jest to dobre, gdy przypisujesz je do zdarzenia onkeyup i daje wynik tak szybko, jak to możliwe.

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

Tutaj możesz z nim zagrać:

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

W przypadku PHP użyj tej funkcji, wykrywa to również niektóre karty podrzędne VISA / MC:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    }

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

1
I pamiętaj, że jest to tylko wykrywanie numeru CC, a nie sprawdzanie poprawności. To jest oddzielone, powinien być czek Luhna ...
Janos Szabo

Gdzie jest Visa Electron i dlaczego czek Maestro zwraca kartę MasterCard w niektórych przypadkach? Czy karta MasterCard nie powinna sama tego sprawdzać?
BadHorsie,

Nie rozpoznaje tego numeru testu JCB jako żadnego z typów (3088514174175777) i identyfikuje ten testowy numer JCB jako diners_club (3096278649822922). Zakładając, że ta lista numerów kart testowych i tak jest ważna ( freeformatter.com/credit-card-number-generator-validator.html )
Drew,

nie ma dokumentacji, że uruchomienie 308 lub 309 może być kartą JCB
Janos Szabo

+1 za dostarczenie kodu wykrywającego typ cc, co zwykle chcesz zrobić dla ux - regex dla nowego zakresu na MC wymaga małego tweeka: / ^ (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";
}

Oto funkcja sprawdzania typu karty kredytowej za pomocą Regex, c #


19

Spójrz na to:

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

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

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

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

15

ostatnio potrzebowałem takiej funkcjonalności, przenosiłem Walidator Zend Framework na Ruby. ruby gem: https://github.com/Fivell/credit_card_validations zend framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

Oba używają zakresów INN do wykrywania typu. Tutaj możesz przeczytać o INN

Zgodnie z tym możesz alternatywnie wykryć kartę kredytową (bez wyrażeń regularnych, ale deklarując pewne zasady dotyczące prefiksów i możliwej długości)

Mamy więc kolejne zasady dotyczące najczęściej używanych kart

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

}

Następnie, wyszukując prefiks i porównując długość, możesz wykryć markę karty kredytowej. Nie zapomnij także o luhn algoritm (jest opisany tutaj http://en.wikipedia.org/wiki/Luhn ).

AKTUALIZACJA

zaktualizowaną listę zasad można znaleźć tutaj https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml


2
Bardzo ilustracyjny. Karty VISA mogą mieć długość 13 cyfr.
Herman Kan

@HermanKan, żadna strona internetowa VISA nie mówi, że powinna mieć długość 16, myślę, że dawno temu mogłaby to być 13, ale nie teraz
Fivell

1
Myślę, że to wsparcie dla starszych wersji
Fivell,

1
@HermanKan, jest jeszcze jedna rzecz, VISA ma karty VPay i wchodząc na wikipedię Marka VPay firmy Visa może określać długości PAN od 13 do 19 cyfr, więc liczba kart powyżej 16 cyfr jest teraz widoczna.
Fivell,

1
@ Ethan, sprawdź ostatni link w mojej zaktualizowanej odpowiedzi raw.githubusercontent.com/Fivell/credit_card_validations/master/…
Fivell

13

Oto kompletny kod C # lub VB dla wszystkich rodzajów CC związanych z projektami kodowymi.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

Ten artykuł jest obecny od kilku lat bez żadnych negatywnych komentarzy.


1
@barett - naprawiono. wygląda na to, że przenieśli go z kategorii „aspnet” do kategorii „sprawdzanie poprawności”, która zmieniła link
Simon_Weaver,

2
Link jest zepsuty. Może to jest to samo narzędzie? codeproject.com/Articles/20271/…
Josh Noe

Ten kod projektu pochodzi z 2007 roku. Ostrzeżenie, może być nieaktualny.
aron

8

Kompaktowa wersja javascript

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

8

Odpowiedź Anatolija w PHP:

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

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

7

Oto funkcja klasy php zwraca CCtype przez CCnumber.
Ten kod nie weryfikuje karty lub nie uruchamia Algorytm Luhna próbuje jedynie znaleźć typ karty kredytowej na podstawie tabeli na tej stronie . zasadniczo używa długości numeru CC i prefiksu karty CC, aby określić typ karty CCcard.

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

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

6

Nie próbuj wykrywać typu karty kredytowej w ramach przetwarzania płatności. Ryzykujesz odrzuceniem ważnych transakcji.

Jeśli musisz podać procesorowi płatności informacje (np. Obiekt karty kredytowej PayPal wymaga podania nazwy rodzaju karty ), zgadnij na podstawie najmniej dostępnych informacji, np.

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

Ta implementacja (wykorzystująca tylko dwie pierwsze cyfry) jest wystarczająca, aby zidentyfikować wszystkie główne (aw przypadku PayPal wszystkie obsługiwane) schematy kart. W rzeczywistości możesz pominąć wyjątek całkowicie i domyślnie wybrać najpopularniejszy typ karty. Niech bramka płatności / procesor poinformuje Cię, czy wystąpił błąd sprawdzania poprawności w odpowiedzi na Twoje żądanie.

Rzeczywistość jest taka, że ​​twoja bramka płatności nie dba o twoją wartość .


1
To jest po prostu nieprawda. Znam 3 różnych dostawców, którzy wymagają przekazania typów kart, a jeśli go nie przekażesz, transakcja się nie powiedzie.
Ed DeGagne

3
@EdDeGagne - „nie dba o jaką wartość” nie jest tym samym, co „nie dba o to, jeśli zostanie przekazany”.
Quentin Skousen

Gdzie ja też to określiłem? Po prostu wspomniałem, że istnieją dostawcy, którzy wymagają od Ciebie podania typu CC, nic więcej.
Ed DeGagne,

nie można uprościć tego złożonego problemu, ale zwykle dostawcy płatności nie wymagają sugerowania rodzaju karty, mają własną metodę wykrywania
Janos Szabo

6

Pierwszych numerów karty kredytowej można użyć do przybliżenia sprzedawcy:

  • Wiza: 49,44 lub 47
  • Wiza elektronowa: 42, 45, 48, 49
  • MasterCard: 51
  • Amex: 34
  • Diners: 30, 36, 38
  • JCB: 35

Zakresy te zostały znacznie zaktualizowane, firmy wydające karty dodały znacznie więcej zakresów niż wspomniano w poście.
NJInamdar,

6

W Card Range Recognition (CRR), wadą algorytmów wykorzystujących serię wyrażeń regularnych lub innych zakodowanych na stałe zakresów jest to, że BIN / IIN zmieniają się w miarę upływu czasu. Co-branding kart jest ciągłą komplikacją. Różni nabywcy / akceptanci kart mogą wymagać traktowania tej samej karty w różny sposób, w zależności np. Od geolokalizacji.

Ponadto w ciągu ostatnich kilku lat, na przykład z kartami UnionPay w szerszym obiegu, istniejące modele nie radzą sobie z nowymi zakresami, które czasami przeplatają się z szerszymi zakresami, które zastępują.
Znajomość położenia geograficznego systemu może pomóc, ponieważ niektóre zakresy są ograniczone do użytku w poszczególnych krajach. Na przykład, zakresy 62 obejmują niektóre podzakresy AAA w USA, ale jeśli twoja baza handlowa znajduje się poza USA, możesz traktować wszystkie 62 jako UnionPay.
Możesz również zostać poproszony o potraktowanie karty inaczej w zależności od lokalizacji sprzedawcy. Na przykład, aby traktować niektóre karty brytyjskie jako debet w kraju, ale jako kredyt międzynarodowy.

Istnieje jeden bardzo użyteczny zestaw zasad utrzymywanych przez jeden duży bank przejmujący. Np. Https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf i https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf . (Ważne linki z czerwca 2017 r., Dzięki użytkownikowi, który podał link do zaktualizowanej referencji). Należy jednak pamiętać o zastrzeżeniu, że chociaż te zasady CRR mogą reprezentować wszechświat wydawania kart, ponieważ dotyczy kupców nabytych przez ten podmiot, nie obejmuje np. zakresów określonych jako CUP / UPI.

Te uwagi dotyczą scenariuszy z paskiem magnetycznym (MagStripe) lub PKE (Pan Key Entry). Znowu sytuacja wygląda inaczej w świecie ICC / EMV.

Aktualizacja: Inne odpowiedzi na tej stronie (a także na połączonej stronie WikiPedia) mają JCB jak zawsze 16. Jednak w mojej firmie mamy dedykowany zespół inżynierów, którzy certyfikują nasze urządzenia POS i oprogramowanie w wielu bankach i lokalizacjach. Najnowszy pakiet certyfikacji kart, które ten zespół ma od JCB, miał skrzynkę na 19-letnią PAN.


Cześć @CaiqueOliveira, zobacz zaktualizowane linki. Podziękowania dla mac9416, który podał link do zaktualizowanego odwołania do reguł BIN.
MikeRoger

1
Dzięki @ mac9416 za zaktualizowane odniesienie do reguł BIN.
MikeRoger

5

Swift 2.1 Wersja odpowiedzi Usmana Y. Skorzystaj z instrukcji print, aby zweryfikować wywołanie za pomocą wartości ciągu

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

func validateCardType(testCard: String) -> String {

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


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


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

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

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

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

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

    return ""

}

4

Stripe zapewnił tę fantastyczną bibliotekę javascript do wykrywania schematów kart. Pozwól, że dodam kilka fragmentów kodu i pokażę, jak z niego korzystać.

Najpierw dołącz go do swojej strony internetowej jako

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

Po drugie, użyj funkcji cardType do wykrycia schematu karty.

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

Oto linki referencyjne, aby uzyskać więcej przykładów i wersji demonstracyjnych.

  1. Blog w paski dla jquery.payment.js
  2. Repozytorium Github

4

W trybie szybkim możesz utworzyć wyliczenie, aby wykryć typ karty kredytowej.

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

Wywołaj metodę CreditCardType.cardTypeForCreditCardNumber („# numer karty”), która zwraca wartość wyliczającą CreditCardType.


3

Moje rozwiązanie z 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;
}

W przypadku zwrotu 0 typ karty kredytowej nie jest wykrywany.

Do pola wejściowego karty kredytowej należy dodać klasę „karta kredytowa”.


1
Różnorodność istniejących odpowiedzi.
Gajus,

1
Tak, użyłem kodu z powyższych odpowiedzi, ULEPSZONO go i opublikowałem tutaj. Dzięki za przegłosowanie ...
ZurabWeb,

3
Powinieneś (a) zasugerować to jako ulepszenie istniejącego kodu, (b) napisać odpowiedni wkład lub (c) odwołać się do źródeł, których użyłeś do napisania wyrażeń regularnych.
Gajus,

1
Gajus, wierzę, że pomogłem społeczności tak, jak mogłem w tej chwili, proszę przestań mówić mi, że powinienem był coś dla kogoś zrobić. Zrobiłem to, co uważałem za pomocne.
ZurabWeb,

3

Dość często szukałem formatowania kart kredytowych i formatowania numerów telefonów. Znalazłem wiele dobrych wskazówek, ale nic tak naprawdę nie pasowało do moich konkretnych pragnień, więc stworzyłem ten kawałek kodu . Używasz go w ten sposób:

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

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

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

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

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


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

$("#signupForm").validate({

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

Pytanie dotyczy algorytmu sprawdzania karty kredytowej, a nie konkretnej implementacji. Co robi ten kod?
Emil Vikström,

2

Tylko mała łyżeczka do karmienia:

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


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

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

        }

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

        }

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

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

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

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

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

        }

    });

2

Oto przykład niektórych funkcji boolowskich napisanych w Pythonie, które zwracają się, Truejeśli karta zostanie wykryta zgodnie z nazwą funkcji.

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


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

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

    return False


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


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


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


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


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


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


# Child cards

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


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


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


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

1

Pierwsze sześć cyfr numeru karty (w tym początkowa cyfra MII) są znane jako numer identyfikacyjny emitenta (IIN). Identyfikują one instytucję wydającą kartę, która wydała kartę posiadaczowi karty. Reszta numeru jest przydzielana przez wydawcę karty. Długość numeru karty to liczba cyfr. Wielu wydawców kart drukuje cały numer IIN i numer konta na swojej karcie.

W oparciu o powyższe fakty chciałbym zachować fragment kodu JAVA w celu identyfikacji marki karty.

Przykładowe typy kart

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

Prefiksy kart

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

Sprawdź, czy numer wejściowy ma dowolny z podanych przedrostków.

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

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

Odniesienie


1

Spróbuj tego dla kotlin. Dodaj Regex i dodaj do instrukcji when.

private fun getCardType(number: String): String {

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

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

0

Reguły wyrażeń regularnych pasujące do odpowiednich dostawców kart :

  • (4\d{12}(?:\d{3})?) dla VISA.
  • (5[1-5]\d{14}) dla MasterCard.
  • (3[47]\d{13}) dla AMEX.
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) dla Maestro.
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) dla Diners Club.
  • (6(?:011|5[0-9]{2})[0-9]{12}) dla Discover.
  • (35[2-8][89]\d\d\d{10}) dla JCB.

Myślę, że wyrażenie regularne dla JCB jest niepoprawne. Wszystkie pierwsze cztery cyfry od 3528 do 3589 powinny zostać zaakceptowane, ale na przykład 3570 nie.
Gabe

0

Używam https://github.com/bendrucker/creditcards-types/ do wykrywania typu karty kredytowej na podstawie numeru. Jednym z problemów, na jakie natrafiłem, jest test nr 6011 1111 1111 1117

z https://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/ możemy zobaczyć, że jest to liczba odkrywcza, ponieważ zaczyna się od 6011. Ale wynik, jaki otrzymuję z typów kart kredytowych, to „Maestro”. Otworzyłem problem autorowi. Odpowiedział mi bardzo szybko i przekazał ten dokument pdf https://www.discovernetwork.com/downloads/IPP_VAR_Compliance.pdf Z tego dokumentu jasno widać, że 6011 1111 1111 1117 nie mieści się w zakresie karty kredytowej Discover.


Mam ten sam problem, czy masz to naprawione?
lucasvm1980,

@ lucasvm1980 Myślę, że plik pdf discovernetwork.com jest bardziej niezawodny. A numer 6011 1111 1111 1117 to tylko numer testowy, żadna prawdziwa karta kredytowa nie ma tego numeru. Myślę więc, że nie muszę się o to martwić.
yuxiaomin

Wygląda na to, że jest jakiś błąd z kartą Discover, próbowałem prawidłowego numeru i ten błąd również się pojawia.
lucasvm1980,

@ lucasvm1980 czy możesz podać numer i zgłosić problem na github?
yuxiaomin,

0

Spróbuj tego. Dla szybkiego.

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
}

Posługiwać się.

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

0
follow Luhn’s algorithm

 private  boolean validateCreditCardNumber(String str) {

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


    }

then call this method

Edittext mCreditCardNumberEt;

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

            }

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

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

                else {
                    cardvalidtesting.setText("");

                }


                }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.