如何根据号码检测信用卡类型?

发布于 2024-07-06 09:06:53 字数 54 浏览 9 评论 0原文

我试图弄清楚如何纯粹根据信用卡号来检测信用卡的类型。 有谁知道找到这个的明确、可靠的方法吗?

I'm trying to figure out how to detect the type of credit card based purely on its number. Does anyone know of a definitive, reliable way to find this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(29

孤城病女 2024-07-13 09:06:53

信用卡/借记卡号称为PAN,或主帐号。 PAN 的前六位数字取自属于发行银行的IIN发行人识别号(IIN 以前称为 BIN - 银行识别号 - 因此您可能会在某些文档中看到对该术语的引用)。 这六位数字受国际标准 ISO/IEC 7812 的约束,并且可以使用从号码判断卡的类型。

遗憾的是,实际的 ISO/IEC 7812 数据库并未公开提供,但有商业和免费的非官方列表,包括 在维基百科上

无论如何,要从数字中检测类型,您可以使用如下正则表达式: Credit for原始表达式

Visa: ^4[0-9]{6,}$ Visa 卡号以 4 开头。

MasterCard: ^5[1-5][0-9]{5,}|222[1-9][0-9]{3,}|22[3-9][0-9]{4 ,}|2[3-6][0-9]{5,}|27[01][0-9]{4,}|2720[0-9]{3,}$ 2016 年之前, MasterCard 号码以数字 51 到 55 开头,但这只会检测 MasterCard 信用卡; 使用万事达卡系统发行的其他卡不属于此 IIN 范围。 2016 年,他们将添加 (222100-272099) 范围内的数字。

American Express: ^3[47][0-9]{5,}$ American Express 卡号以 34 或 37 开头。

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ Diners Club 卡号以 300 到 305 开头, 36 或 38。有些 Diners Club 卡以 5 开头,有 16 位数字。 这些是 Diners Club 和万事达卡之间的合资企业,应像万事达卡一样进行处理。

发现: ^6(?:011|5[0-9]{2})[0-9]{3,}$ 发现卡号以 6011 或65.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ JCB 卡开头为2131、1800 或 35。

不幸的是,MasterCard 系统处理的许多卡类型不在 MasterCard 的 IIN 范围内(编号从 51...55 开始); 最重要的例子是 Maestro 卡,其中许多卡是从其他银行的 IIN 范围发行的,因此遍布整个号码空间。 因此,最好假设任何非您接受的其他类型的卡都必须是万事达卡

重要:卡号的长度确实有所不同; 例如,Visa 过去发行过 13 位 PAN 的卡和 16 位 PAN 的卡。 Visa 的文件目前表明它可能会签发或可能已经签发了 12 到 19 位数字的号码。 因此,您不应检查卡号的长度,除非验证卡号至少有 7 位(对于完整的 IIN 加上一位校验位,应与 Luhn 算法)。

进一步提示:在处理持卡人 PAN 之前,从输入中去除所有空格和标点符号。 为什么? 因为通常更容易按组输入数字,类似于它们在实际信用卡正面的显示方式,即

4444 4444 4444 4444

比正确输入要容易得多

4444444444444444

。用户,因为他们输入了您不期望的字符。

这还意味着确保您的输入字段有空间至少 24 个字符,否则输入空格的用户将耗尽空间。我建议您将字段宽度足以显示 32 个字符,最多允许 64 个; 这为扩展提供了充足的空间。

下面的图片可以提供更多见解:

更新 (2016): 万事达卡将从 开始实施新的 BIN 范围付款方式

信用卡验证

The credit/debit card number is referred to as a PAN, or Primary Account Number. The first six digits of the PAN are taken from the IIN, or Issuer Identification Number, belonging to the issuing bank (IINs were previously known as BIN — Bank Identification Numbers — so you may see references to that terminology in some documents). These six digits are subject to an international standard, ISO/IEC 7812, and can be used to determine the type of card from the number.

Unfortunately the actual ISO/IEC 7812 database is not publicly available, however, there are unofficial lists, both commercial and free, including on Wikipedia.

Anyway, to detect the type from the number, you can use a regular expression like the ones below: Credit for original expressions

Visa: ^4[0-9]{6,}$ Visa card numbers start with a 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,}$ Before 2016, MasterCard numbers start with the numbers 51 through 55, but this will only detect MasterCard credit cards; there are other cards issued using the MasterCard system that do not fall into this IIN range. In 2016, they will add numbers in the range (222100-272099).

American Express: ^3[47][0-9]{5,}$ American Express card numbers start with 34 or 37.

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ Diners Club card numbers begin with 300 through 305, 36 or 38. There are Diners Club cards that begin with 5 and have 16 digits. These are a joint venture between Diners Club and MasterCard and should be processed like a MasterCard.

Discover: ^6(?:011|5[0-9]{2})[0-9]{3,}$ Discover card numbers begin with 6011 or 65.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ JCB cards begin with 2131, 1800 or 35.

Unfortunately, there are a number of card types processed with the MasterCard system that do not live in MasterCard’s IIN range (numbers starting 51...55); the most important case is that of Maestro cards, many of which have been issued from other banks’ IIN ranges and so are located all over the number space. As a result, it may be best to assume that any card that is not of some other type you accept must be a MasterCard.

Important: card numbers do vary in length; for instance, Visa has in the past issued cards with 13 digit PANs and cards with 16 digit PANs. Visa’s documentation currently indicates that it may issue or may have issued numbers with between 12 and 19 digits. Therefore, you should not check the length of the card number, other than to verify that it has at least 7 digits (for a complete IIN plus one check digit, which should match the value predicted by the Luhn algorithm).

One further hint: before processing a cardholder PAN, strip any whitespace and punctuation characters from the input. Why? Because it’s typically much easier to enter the digits in groups, similar to how they’re displayed on the front of an actual credit card, i.e.

4444 4444 4444 4444

is much easier to enter correctly than

4444444444444444

There’s really no benefit in chastising the user because they’ve entered characters you don't expect here.

This also implies making sure that your entry fields have room for at least 24 characters, otherwise users who enter spaces will run out of room. I’d recommend that you make the field wide enough to display 32 characters and allow up to 64; that gives plenty of headroom for expansion.

Here's an image that gives a little more insight:

UPDATE (2016): Mastercard is to implement new BIN ranges starting Ach Payment.

Credit Card Verification

终弃我 2024-07-13 09:06:53

在 javascript 中:

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

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

单元测试:

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

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

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

            '5019000000000000': 'DANKORT',

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

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

            '6360000000000000': 'INTERPAYMENT',

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

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

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

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

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

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

Unit test:

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]);
            });
        });
    });
});
逆夏时光 2024-07-13 09:06:53

更新日期:2016 年 6 月 15 日(作为当前的最终解决方案)

请注意,我什至对投票最高的一个进行了投票,但为了清楚起见,这些正则表达式实际上有效,我对数千个进行了测试真实的 BIN 代码。 最重要的是使用起始字符串(^),否则在现实世界中会给出错误的结果!

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

美国运通 ^3[47] [0-9]{0,}$ 开头:34, 37

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

签证 ^4[0-9]{0,}$ 开头:4

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

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro 始终在该范围内增长:60-69,以 / 开头,不是别的,但开头 5 无论如何都必须编码为 mastercard。 Maestro 卡必须在代码末尾被检测到,因为其他一些卡的范围在 60-69 之间。 请看一下代码。

发现 ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]| 62292[0-5])[0-9]{0,}$ 发现编码相当困难,从以下内容开始:6011, 622126-622925, 644-649, 65

In < strong>javascript 我使用这个函数。 当您将其分配给 onkeyup 事件并尽快给出结果时,这很好。

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

    //JCB
    jcb_regex = new RegExp('^(?:2131|1800|35)[0-9]{0,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    }

    return "unknown"; //unknown for this system
}
); //2131, 1800, 35 (3528-3589) // American Express amex_regex = new RegExp('^3[47][0-9]{0,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:


); //34, 37
    // Diners Club
    diners_regex = new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:


); //300-305, 309, 36, 38-39
    // Visa
    visa_regex = new RegExp('^4[0-9]{0,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:


); //4
    // MasterCard
    mastercard_regex = new RegExp('^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:


); //2221-2720, 51-55
    maestro_regex = new RegExp('^(5[06789]|6)[0-9]{0,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:


); //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,}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:


);
    ////6011, 622126-622925, 644-649, 65


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

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

    return sel_brand;
}

您可以在这里使用它:

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

对于 PHP 使用此函数,这也会检测到一些子 VISA/MC 卡:

Updated: 15th June 2016 (as an ultimate solution currently)

Please note that I even give vote up for the one is top voted, but to make it clear these are the regexps actually works i tested it with thousands of real BIN codes. The most important is to use start strings (^) otherwise it will give false results in real world!

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

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

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

Visa ^4[0-9]{0,}$ Start with: 4

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

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro always growing in the range: 60-69, started with / not something else, but starting 5 must be encoded as mastercard anyway. Maestro cards must be detected in the end of the code because some others has in the range of 60-69. Please look at the code.

Discover ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ Discover quite difficult to code, start with: 6011, 622126-622925, 644-649, 65

In javascript I use this function. This is good when u assign it to an onkeyup event and it give result as soon as possible.

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

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:

/**
  * 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
}
); //2131, 1800, 35 (3528-3589) // American Express amex_regex = new RegExp('^3[47][0-9]{0,}

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:


); //34, 37
    // Diners Club
    diners_regex = new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:


); //300-305, 309, 36, 38-39
    // Visa
    visa_regex = new RegExp('^4[0-9]{0,}

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:


); //4
    // MasterCard
    mastercard_regex = new RegExp('^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:


); //2221-2720, 51-55
    maestro_regex = new RegExp('^(5[06789]|6)[0-9]{0,}

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:


); //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,}

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:


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

Here you can play with it:

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

For PHP use this function, this detects some sub VISA/MC cards too:

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


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

这是使用 Regex 检查信用卡类型的函数,c#

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

Here is the function to check Credit card type using Regex , c#

稀香 2024-07-13 09:06:53

看看这个:

http://www.writingpar.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;
}

Check this out:

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;
}
天气好吗我好吗 2024-07-13 09:06:53

最近我需要这样的功能,我正在将 Zend Framework Credit Card Validator 移植到 ruby​​。
红宝石宝石: https://github.com/Fivell/credit_card_validations
zend 框架: https://github.com/zendframework /zf2/blob/master/library/Zend/Validator/CreditCard.php

它们都使用 INN 范围来检测类型。 在这里你可以阅读关于INN

根据这个你可以检测信用卡(没有正则表达式,但是声明一些关于前缀和可能长度的规则)

所以我们对最常用的卡有下一个规则

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

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

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

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

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

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

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


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

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

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

    ],

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

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

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

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

}

然后通过搜索前缀和比较长度您可以检测信用卡品牌。 另外不要忘记 luhn 算法(这里有描述 http://en.wikipedia.org/wiki /卢恩)。

可以在此处找到更新

的规则列表 https://raw .githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml

recently I needed such functionality, I was porting Zend Framework Credit Card Validator to ruby.
ruby gem: https://github.com/Fivell/credit_card_validations
zend framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

They both use INN ranges for detecting type. Here you can read about INN

According to this you can detect credit card alternatively (without regexps,but declaring some rules about prefixes and possible length)

So we have next rules for most used cards

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

}

Then by searching prefix and comparing length you can detect credit card brand. Also don't forget about luhn algoritm (it is descibed here http://en.wikipedia.org/wiki/Luhn).

UPDATE

updated list of rules can be found here https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml

我很坚强 2024-07-13 09:06:53

这里是 所有与 CC 相关的内容的完整 C# 或 VB 代码 在代码项目上。

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

这篇文章已经发表了几年,没有负面评论。

Here's Complete C# or VB code for all kinds of CC related things on codeproject.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

This article has been up for a couple years with no negative comments.

留蓝 2024-07-13 09:06:53

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

Anatoliy's answer in 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;
    }
 }
已下线请稍等 2024-07-13 09:06:53

紧凑的 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;
            }
        }
    };

Compact javascript version

    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;
            }
        }
    };
橘香 2024-07-13 09:06:53

在卡片范围识别 (CRR) 中,使用一系列正则表达式或其他硬编码范围的算法的一个缺点是,根据我的经验,BIN/IIN 确实会随着时间而变化。 卡片的联合品牌是一个持续存在的复杂问题。 不同的卡收单机构/商户可能需要您以不同的方式对待同一张卡,具体取决于地理位置等。

此外,在过去几年中,随着银联卡等的广泛流通,现有模型无法应对新的范围,这些范围有时会与它们所取代的更广泛的范围交织在一起。
了解您的系统需要覆盖的地理位置可能会有所帮助,因为某些范围仅限于特定国家/地区使用。 例如,范围 62 包括美国的一些 AAA 子范围,但如果您的商户基地位于美国境外,您也许可以将所有 62 视为银联。
您可能还会被要求根据商户位置对卡进行不同的处理。 例如,将某些英国卡在国内视为借记卡,但在国际上视为信用卡。

一家主要收单银行维护了一套非常有用的规则。 例如 https://www.barclaycard.co.uk/business /files/BIN-Rules-EIRE.pdfhttps://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf。 (截至 2017 年 6 月的有效链接,感谢提供更新参考链接的用户。)但请注意,虽然这些 CRR 规则可能代表发卡领域,因为它适用于该实体收购的商户,它不包括例如标识为 CUP/UPI 的范围。

这些注释适用于磁条 (MagStripe) 或 PKE (Pan Key Entry) 场景。 ICC/EMV 领域的情况又有所不同。

更新:此页面(以及链接的维基百科页面)上的其他答案的 JCB 一如既往地为 16 长。 然而,在我的公司,我们有一支专门的工程师团队,负责在多个收单银行和地区对我们的 POS 设备和软件进行认证。 该团队从 JCB 获得的最新认证卡包有一个 19 长 PAN 的通行证盒。

In Card Range Recognition (CRR), a drawback with algorithms that use a series of regex or other hard-coded ranges, is that the BINs/IINs do change over time in my experience. The co-branding of cards is an ongoing complication. Different Card Acquirers / merchants may need you treat the same card differently, depending on e.g. geolocation.

Additionally, in the last few years with e.g. UnionPay cards in wider circulation, existing models do not cope with new ranges that sometimes interleave with broader ranges that they supersede.
Knowing the geography your system needs to cover may help, as some ranges are restricted to use in particular countries. For example, ranges 62 include some AAA sub-ranges in the US, but if your merchant base is outside the US, you may be able to treat all 62 as UnionPay.
You may be also asked to treat a card differently based on merchant location. E.g. to treat certain UK cards as debit domestically, but as credit internationally.

There are very useful set of rules maintained by one major Acquiring Bank. E.g. https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf and https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf. (Valid links as of June 2017, thanks to the user who provided a link to updated reference.) But be aware of the caveat that, while these CRR rules may represent the Card Issuing universe as it applies to the merchants acquired by that entity, it does not include e.g. ranges identified as CUP/UPI.

These comments apply to magnetic stripe (MagStripe) or PKE (Pan Key Entry) scenarios. The situation is different again in the ICC/EMV world.

Update: Other answers on this page (and also the linked WikiPedia page) have JCB as always 16 long. However, in my company we have a dedicated team of engineers who certify our POS devices and software across multiple acquiring banks and geographies. The most recent Certification Pack of cards this team have from JCB, had a pass case for a 19 long PAN.

¢好甜 2024-07-13 09:06:53

这是一个 php 类函数,按 CCnumber 返回 CCtype。

此代码不验证卡或不运行 Luhn 算法,仅尝试根据 此页面。 基本上使用CCnumber长度和CCcard前缀来确定CCcard类型。

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

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

Here is a php class function returns CCtype by CCnumber.

This code not validates the card or not runs Luhn algorithm only try to find credit card type based on table in this page. basicly uses CCnumber length and CCcard prefix to determine CCcard type.

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

青丝拂面 2024-07-13 09:06:53

信用卡的前几个数字可用于估计供应商:

  • Visa:49,44 或 47
  • Visa electro:42、45、48、49
  • MasterCard:51
  • Amex:34
  • Diners:30、36、38
  • JCB:35

The first numbers of the credit card can be used to approximate the vendor:

  • Visa: 49,44 or 47
  • Visa electron: 42, 45, 48, 49
  • MasterCard: 51
  • Amex:34
  • Diners: 30, 36, 38
  • JCB: 35
或十年 2024-07-13 09:06:53

不要尝试在处理付款时检测信用卡类型。 您面临着拒绝有效交易的风险。

如果您需要向支付处理方提供信息(例如 PayPal 信用卡对象需要命名 卡类型),然后从最少的可用信息中猜测它,例如

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

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

此实现(仅使用前两位数字)足以识别所有主要的(在 PayPal 的情况下是所有受支持的)卡计划。 事实上,您可能想完全跳过例外并默认使用最流行的卡类型。 让支付网关/处理器告诉您在响应您的请求时是否存在验证错误。

现实情况是,您的支付网关并不关心您提供的价值

Do not try to detect credit card type as part of processing a payment. You are risking of declining valid transactions.

If you need to provide information to your payment processor (e.g. PayPal credit card object requires to name the card type), then guess it from the least information available, e.g.

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

This implementation (using only the first two digits) is enough to identify all of the major (and in PayPal's case all of the supported) card schemes. In fact, you might want to skip the exception altogether and default to the most popular card type. Let the payment gateway/processor tell you if there is a validation error in response to your request.

The reality is that your payment gateway does not care about the value you provide.

独留℉清风醉 2024-07-13 09:06:53

Usman Y 的答案的 Swift 2.1 版本。
使用 print 语句通过某个字符串值验证 so 调用

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

}

Swift 2.1 Version of Usman Y's answer.
Use a print statement to verify so call by some string value

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

}
仅此而已 2024-07-13 09:06:53

Stripe 提供了这个出色的 javascript 库用于卡方案检测。 让我添加一些代码片段并向您展示如何使用它。

首先将其添加到您的网页中,然后

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

使用函数cardType 来检测卡方案。

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

以下是更多示例和演示的参考链接。

  1. jquery. payment.js 的 Stripe 博客
  2. Github 存储库

Stripe has provided this fantastic javascript library for card scheme detection. Let me add few code snippets and show you how to use it.

Firstly Include it to your web page as

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

Secondly use the function cardType for detecting the card scheme.

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

Here are the reference links for more examples and demos.

  1. Stripe blog for jquery.payment.js
  2. Github repository
瞎闹 2024-07-13 09:06:53

您可以快速创建一个枚举来检测信用卡类型。

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

case Visa
case Master
case Amex
case Discover

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

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

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

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

    return regex
}

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

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

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

调用 CreditCardType.cardTypeForCreditCardNumber("#card number") 方法,该方法返回 CreditCardType 枚举值。

In swift you can create an enum to detect the credit card type.

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

Call the method CreditCardType.cardTypeForCreditCardNumber("#card number") which returns CreditCardType enum value.

微凉 2024-07-13 09:06:53

@Anatoliy 答案的 javascript 改进

function getCardType (number) {
  const numberFormated = number.replace(/\D/g, '')
  var patterns = {
    VISA: /^4[0-9]{12}(?:[0-9]{3})?$/,
    MASTER: /^5[1-5][0-9]{14}$/,
    AMEX: /^3[47][0-9]{13}$/,
    ELO: /^((((636368)|(438935)|(504175)|(451416)|(636297))\d{0,10})|((5067)|(4576)|(4011))\d{0,12})$/,
    AURA: /^(5078\d{2})(\d{2})(\d{11})$/,
    JCB: /^(?:2131|1800|35\d{3})\d{11}$/,
    DINERS: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
    DISCOVERY: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
    HIPERCARD: /^(606282\d{10}(\d{3})?)|(3841\d{15})$/,
    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+$/,
  }
  for (var key in patterns) {
    if (patterns[key].test(numberFormated)) {
      return key
    }
  }
}

console.log(getCardType("4539 5684 7526 2091"))

A javascript improve of @Anatoliy answer

function getCardType (number) {
  const numberFormated = number.replace(/\D/g, '')
  var patterns = {
    VISA: /^4[0-9]{12}(?:[0-9]{3})?$/,
    MASTER: /^5[1-5][0-9]{14}$/,
    AMEX: /^3[47][0-9]{13}$/,
    ELO: /^((((636368)|(438935)|(504175)|(451416)|(636297))\d{0,10})|((5067)|(4576)|(4011))\d{0,12})$/,
    AURA: /^(5078\d{2})(\d{2})(\d{11})$/,
    JCB: /^(?:2131|1800|35\d{3})\d{11}$/,
    DINERS: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
    DISCOVERY: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
    HIPERCARD: /^(606282\d{10}(\d{3})?)|(3841\d{15})$/,
    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+$/,
  }
  for (var key in patterns) {
    if (patterns[key].test(numberFormated)) {
      return key
    }
  }
}

console.log(getCardType("4539 5684 7526 2091"))
溺渁∝ 2024-07-13 09:06:53

我的 jQuery 解决方案:

function detectCreditCardType() {
    var type = new Array;
    type[1] = '^4[0-9]{12}(?:[0-9]{3})?

如果返回 0,则未检测到信用卡类型。

应将“creditcard”类添加到信用卡输入字段中。

; // visa type[2] = '^5[1-5][0-9]{14}

如果返回 0,则未检测到信用卡类型。

应将“creditcard”类添加到信用卡输入字段中。

; // mastercard type[3] = '^6(?:011|5[0-9]{2})[0-9]{12}

如果返回 0,则未检测到信用卡类型。

应将“creditcard”类添加到信用卡输入字段中。

; // discover type[4] = '^3[47][0-9]{13}

如果返回 0,则未检测到信用卡类型。

应将“creditcard”类添加到信用卡输入字段中。

; // amex var ccnum = $('.creditcard').val().replace(/[^\d.]/g, ''); var returntype = 0; $.each(type, function(idx, re) { var regex = new RegExp(re); if(regex.test(ccnum) && idx>0) { returntype = idx; } }); return returntype; }

如果返回 0,则未检测到信用卡类型。

应将“creditcard”类添加到信用卡输入字段中。

My solution with jQuery:

function detectCreditCardType() {
    var type = new Array;
    type[1] = '^4[0-9]{12}(?:[0-9]{3})?

In case 0 is returned, credit card type is undetected.

"creditcard" class should be added to the credit card input field.

; // visa type[2] = '^5[1-5][0-9]{14}

In case 0 is returned, credit card type is undetected.

"creditcard" class should be added to the credit card input field.

; // mastercard type[3] = '^6(?:011|5[0-9]{2})[0-9]{12}

In case 0 is returned, credit card type is undetected.

"creditcard" class should be added to the credit card input field.

; // discover type[4] = '^3[47][0-9]{13}

In case 0 is returned, credit card type is undetected.

"creditcard" class should be added to the credit card input field.

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

In case 0 is returned, credit card type is undetected.

"creditcard" class should be added to the credit card input field.

只是偏爱你 2024-07-13 09:06:53

我搜索了很多信用卡格式和电话号码格式。 发现了很多好的技巧,但没有什么真正适合我的需求,所以我创建了这段代码。 你像这样使用它:

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

I searched around quite a bit for credit card formatting and phone number formatting. Found lots of good tips but nothing really suited my exact desires so I created this bit of code. You use it like this:

var sf = smartForm.formatCC(myInputString);
var cardType = sf.cardType;
梦境 2024-07-13 09:06:53

Swift 5+

extension String {
    
    func isMatch(_ Regex: String) -> Bool {
        
        do {
            let regex = try NSRegularExpression(pattern: Regex)
            let results = regex.matches(in: self, range: NSRange(self.startIndex..., in: self))
            return results.map {
                String(self[Range($0.range, in: self)!])
            }.count > 0
        } catch {
            return false
        }
        
    }
    
    func getCreditCardType() -> String? {
        
        let VISA_Regex = "^4[0-9]{6,}$"
        let MasterCard_Regex = "^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,}$"
        let AmericanExpress_Regex = "^3[47][0-9]{5,}$"
        let DinersClub_Regex = "^3(?:0[0-5]|[68][0-9])[0-9]{4,}$"
        let Discover_Regex = "^6(?:011|5[0-9]{2})[0-9]{3,}$"
        let JCB_Regex = "^(?:2131|1800|35[0-9]{3})[0-9]{3,}$"
        
        if self.isMatch(VISA_Regex) {
            return "VISA"
        } else if self.isMatch(MasterCard_Regex) {
            return "MasterCard"
        } else if self.isMatch(AmericanExpress_Regex) {
            return "AmericanExpress"
        } else if self.isMatch(DinersClub_Regex) {
            return "DinersClub"
        } else if self.isMatch(Discover_Regex) {
            return "Discover"
        } else if self.isMatch(JCB_Regex) {
            return "JCB"
        } else {
            return nil
        }
        
    }
    
}

使用。

"1234123412341234".getCreditCardType()

Swift 5+

extension String {
    
    func isMatch(_ Regex: String) -> Bool {
        
        do {
            let regex = try NSRegularExpression(pattern: Regex)
            let results = regex.matches(in: self, range: NSRange(self.startIndex..., in: self))
            return results.map {
                String(self[Range($0.range, in: self)!])
            }.count > 0
        } catch {
            return false
        }
        
    }
    
    func getCreditCardType() -> String? {
        
        let VISA_Regex = "^4[0-9]{6,}
quot;
        let MasterCard_Regex = "^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,}
quot;
        let AmericanExpress_Regex = "^3[47][0-9]{5,}
quot;
        let DinersClub_Regex = "^3(?:0[0-5]|[68][0-9])[0-9]{4,}
quot;
        let Discover_Regex = "^6(?:011|5[0-9]{2})[0-9]{3,}
quot;
        let JCB_Regex = "^(?:2131|1800|35[0-9]{3})[0-9]{3,}
quot;
        
        if self.isMatch(VISA_Regex) {
            return "VISA"
        } else if self.isMatch(MasterCard_Regex) {
            return "MasterCard"
        } else if self.isMatch(AmericanExpress_Regex) {
            return "AmericanExpress"
        } else if self.isMatch(DinersClub_Regex) {
            return "DinersClub"
        } else if self.isMatch(Discover_Regex) {
            return "Discover"
        } else if self.isMatch(JCB_Regex) {
            return "JCB"
        } else {
            return nil
        }
        
    }
    
}

Use.

"1234123412341234".getCreditCardType()
一个人的旅程 2024-07-13 09:06:53
// 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">  <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
       },
// 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">  <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
       },
想念有你 2024-07-13 09:06:53

只需用勺子喂一点:

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

        }

    });

Just a little spoon feeding:

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

        }

    });
一抹苦笑 2024-07-13 09:06:53

以下是用 Python 编写的一些布尔函数的示例,如果根据函数名称检测到卡,则返回 True。

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


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

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

    return False


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


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


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


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


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


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


# Child cards

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


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


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


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

Here is an example of some boolean functions written in Python that return True if the card is detected as per the function name.

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
七婞 2024-07-13 09:06:53

卡号的前六位数字(包括开头的MII)
数字)被称为发卡机构识别号 (IIN)。 这些
识别该卡的发卡机构
持有者。 其余数量由发卡机构分配。 这
卡号的长度是其位数。 许多发卡机构打印
其卡上的完整 IIN 和帐号。

基于上述事实,我想保留一段JAVA代码来识别卡品牌。

卡片类型示例

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

卡片前缀

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

检查输入号码是否具有任何给定的前缀。

public String getBrand(String number) {

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

最后,实用方法

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

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

参考

The first six digits of a card number (including the initial MII
digit) are known as the issuer identification number (IIN). These
identify the card issuing institution that issued the card to the card
holder. The rest of the number is allocated by the card issuer. The
card number's length is its number of digits. Many card issuers print
the entire IIN and account number on their card.

Based on the above facts I would like to keep a snippet of JAVA code to identify card brand.

Sample card types

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

Card Prefixes

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

Check to see if the input number has any of the given prefixes.

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

Finally, The Utility method

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

Reference

蓝咒 2024-07-13 09:06:53
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) {

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

            }
        });
半﹌身腐败 2024-07-13 09:06:53

在 kotlin 上试试这个。 添加正则表达式并添加到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"
        }
    }

Try this for kotlin. Add Regex and add to the when statement.

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"
        }
    }
临走之时 2024-07-13 09:06:53

分别与 匹配的正则表达式规则卡供应商

  • (4\d{12}(?:\d{3})?) 对于 VISA。
  • (5[1-5]\d{14}) 对于万事达卡。
  • (3[47]\d{13}) 用于美国运通 (AMEX)。
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) 对于 Maestro。
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) 代表 Diners Club。
  • (6(?:011|5[0-9]{2})[0-9]{12}) 用于发现。
  • (35[2-8][89]\d\d\d{10}) JCB。

The regular expression rules that match the respective card vendors:

  • (4\d{12}(?:\d{3})?) for VISA.
  • (5[1-5]\d{14}) for MasterCard.
  • (3[47]\d{13}) for AMEX.
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) for Maestro.
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) for Diners Club.
  • (6(?:011|5[0-9]{2})[0-9]{12}) for Discover.
  • (35[2-8][89]\d\d\d{10}) for JCB.
山田美奈子 2024-07-13 09:06:53

另一个api解决方案在rapidapi 银行卡Bin Num Check有250K+ 发行卡类型。

只有一个 GET Rest api 请求并获取发卡机构信息,例如:

{ "bin_number": 535177, "bank": "Finansbank A.S.", "scheme": "MASTERCARD", "type": "Debit", "country": "Turkey" }

Another api solution at rapidapi Bank Card Bin Num Check there are 250K+ issued card type.

Only one GET rest api request and get card issuer info like:

{ "bin_number": 535177, "bank": "Finansbank A.S.", "scheme": "MASTERCARD", "type": "Debit", "country": "Turkey" }
余生再见 2024-07-13 09:06:53

基于该组规则: https://raw.githubusercontent Fivell 在这篇文章中提供的 .com/Fivell/credit_card_validations/master/lib/data/brands.yaml 我创建了该 php 方法:

    public static function identifyCardType($cardNumber)
    {
        $cardTypes = [
            'visa' => [
                'rules' => [['length' => [13, 16, 19], 'prefixes' => ['4']]],
                'options' => ['brand_name' => 'Visa'],
            ],
            'mastercard' => [
                'rules' => [['length' => [16], 'prefixes' => [
                    '2221', '2222', '2223', '2224', '2225', '2226', '2227', '2228', '2229',
                    '223', '224', '225', '226', '227', '228', '229', '23', '24', '25', '26', '271', '2720', '51', '52', '53', '54', '55'
                ]]],
                'options' => ['brand_name' => 'MasterCard'],
            ],
            'amex' => [
                'rules' => [['length' => [15], 'prefixes' => ['34', '37']]],
                'options' => ['brand_name' => 'American Express'],
            ],
            'diners' => [
                'rules' => [['length' => [14], 'prefixes' => ['300', '301', '302', '303', '304', '305', '36', '38']]],
                'options' => ['brand_name' => 'Diners Club'],
            ],
            'jcb' => [
                'rules' => [
                    ['length' => [15, 16], 'prefixes' => ['3528', '3529', '353', '354', '355', '356', '357', '358']],
                    ['length' => [15], 'prefixes' => ['1800', '2131']],
                    ['length' => [19], 'prefixes' => ['357266']],
                ],
                'options' => ['brand_name' => 'JCB'],
            ],
            'solo' => [
                'rules' => [['length' => [16, 18, 19], 'prefixes' => ['6334', '6767']]],
                'options' => ['brand_name' => 'Solo'],
            ],
            'maestro' => [
                'rules' => [
                    ['length' => [12, 13, 14, 15, 16, 17, 18, 19], 'prefixes' => [
                        '500', '5010', '5011', '5012', '5013', '5014', '5015', '5016', '5017', '5018', '502', '503', '504',
                        '505', '506', '507', '508', '509', '56', '57', '58', '59', '6010', '6012', '6013', '6014', '6015', '6016', '6017', '6018', '6019', '602', '603', '604', '605', '6060', '616788', '62183', '62186', '62188', '62198', '62199', '6220', '622110', '627089', '62709601', '6271', '6272', '6273', '6274', '6275', '6276', '6277', '6278', '6279', '6280', '6281', '6294', '6301', '630490', '633857', '63609', '6361', '636392', '636708', '637043', '637102', '637118', '637187', '637529', '639', '640', '641', '642', '643', '670', '671', '672', '673', '674', '675', '677', '6760', '6761', '6762', '6763', '6764', '6765', '6766', '6768', '6769', '6771', '679'
                    ]]
                ],
                'options' => ['brand_name' => 'Maestro'],
            ],
            'electron' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => ['4026', '417500', '4405', '4508', '4844', '4913', '4917']]
                ],
                'options' => ['brand_name' => 'Visa Electron'],
            ],
            'unionpay' => [
                'rules' => [
                    ['length' => [16, 17, 18, 19], 'prefixes' => [
                        '620', '6210', '6212', '6213', '6214', '6215', '6216', '6217', '621977', '622126', '622127', '622128', '622129',
                        '62213', '62214', '62215', '62216', '62217', '62218', '62220', '62221', '62222', '62223', '62224', '62225',
                        '62226', '62227', '62228', '62229', '6223', '6224', '6225', '6226', '6227', '6228', '6229', '623', '624',
                        '625', '626', '62702', '62704', '62706', '62707', '6282', '6283', '6284', '6291', '6292', '632062', '685800',
                        '69075'
                    ]]
                ],
                'options' => ['brand_name' => 'China UnionPay', 'skip_luhn' => true],
            ],
            'discover' => [
                'rules' => [
                    ['length' => [16, 19], 'prefixes' => [
                        '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'
                    ]]
                ],
                'options' => ['brand_name' => 'Discover'],
            ],
            'rupay' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => [
                        '6061', '6062', '6063', '6064', '6065', '6066', '6067', '6068', '6069', '607', '608'
                    ]]
                ],
                'options' => ['brand_name' => 'RuPay', 'skip_luhn' => true],
            ],
            'hipercard' => [
                'rules' => [
                    ['length' => [19], 'prefixes' => [
                        '384100', '384140', '384160', '606282', '637095', '637568', '637599', '637609', '637612'
                    ]]
                ],
                'options' => ['brand_name' => 'Hipercard'],
            ],
            'elo' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => [
                        '401178', '401179', '431274', '438935', '451416', '457393', '457631', '457632', '504175', '506699', '50670', '50671',
                        '506717', '506718', '50672', '506720', '506721', '506724', '506725', '506726', '506727', '506728', '506729', '50673',
                        '50674', '50675', '50676', '506770', '506771', '506772', '506773', '506774', '506775', '506776', '506777', '506778',
                        '50900', '509013', '50902', '509031', '509033', '509035', '509036', '509037', '509038', '509039', '50904', '509050',
                        '509051', '509052', '509053', '509064', '509066', '509067', '509068', '509069', '509072', '509074', '509076', '509077',
                        '509078', '509079', '509080', '509081', '509082', '509083', '509085', '636297', '636368', '650031', '650032', '650033',
                        '650035', '650036', '650037', '650038', '650039', '65004', '650050', '650051', '650405', '650406', '650407', '650408',
                        '650409', '65041', '65042', '65043', '650485', '650486', '650487', '650488', '650489', '65049', '65050', '65051', '65052',
                        '650530', '650531', '650532', '650533', '650534', '650535', '650536', '650537', '650538', '650541', '650700', '650720',
                        '650901', '650921', '650922', '650923', '650924', '650925', '650926', '650927', '650928', '650929', '65093', '65094',
                        '65095', '65096', '650970', '650971', '650972', '650973', '650974', '650975', '650976', '650977', '650978', '651652',
                        '65500', '65501', '655021', '65503', '65504'
                    ]]
                ],
                'options' => ['brand_name' => 'Elo'],
            ],
            'mir' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => [
                        '2200', '2201', '2202', '2203', '2204'
                    ]]
                ],
                'options' => ['brand_name' => 'Mir'],
            ],
            'dankort' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => ['5019']]
                ],
                'options' => ['brand_name' => 'Dankort'],
            ],
            'switch' => [
                'rules' => [
                    ['length' => [16, 18, 19], 'prefixes' => [
                        '4903', '4905', '4911', '4936', '564182', '633110', '6333', '6759'
                    ]]
                ],
                'options' => ['brand_name' => 'Switch'],
            ]            
            
        ];

        foreach ($cardTypes as $type => $data) {
            foreach ($data['rules'] as $rule) {
                if (in_array(strlen($cardNumber), $rule['length'])) {
                    foreach ($rule['prefixes'] as $prefix) {
                        if (strpos($cardNumber, $prefix) === 0) {
                            return isset($data['options']['brand_name']) ? $data['options']['brand_name'] : null;
                        }
                    }
                }
            }
        }

        return 'Unknown';
    }

Based on that set of rules : https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml provided in this post by Fivell I created that php method :

    public static function identifyCardType($cardNumber)
    {
        $cardTypes = [
            'visa' => [
                'rules' => [['length' => [13, 16, 19], 'prefixes' => ['4']]],
                'options' => ['brand_name' => 'Visa'],
            ],
            'mastercard' => [
                'rules' => [['length' => [16], 'prefixes' => [
                    '2221', '2222', '2223', '2224', '2225', '2226', '2227', '2228', '2229',
                    '223', '224', '225', '226', '227', '228', '229', '23', '24', '25', '26', '271', '2720', '51', '52', '53', '54', '55'
                ]]],
                'options' => ['brand_name' => 'MasterCard'],
            ],
            'amex' => [
                'rules' => [['length' => [15], 'prefixes' => ['34', '37']]],
                'options' => ['brand_name' => 'American Express'],
            ],
            'diners' => [
                'rules' => [['length' => [14], 'prefixes' => ['300', '301', '302', '303', '304', '305', '36', '38']]],
                'options' => ['brand_name' => 'Diners Club'],
            ],
            'jcb' => [
                'rules' => [
                    ['length' => [15, 16], 'prefixes' => ['3528', '3529', '353', '354', '355', '356', '357', '358']],
                    ['length' => [15], 'prefixes' => ['1800', '2131']],
                    ['length' => [19], 'prefixes' => ['357266']],
                ],
                'options' => ['brand_name' => 'JCB'],
            ],
            'solo' => [
                'rules' => [['length' => [16, 18, 19], 'prefixes' => ['6334', '6767']]],
                'options' => ['brand_name' => 'Solo'],
            ],
            'maestro' => [
                'rules' => [
                    ['length' => [12, 13, 14, 15, 16, 17, 18, 19], 'prefixes' => [
                        '500', '5010', '5011', '5012', '5013', '5014', '5015', '5016', '5017', '5018', '502', '503', '504',
                        '505', '506', '507', '508', '509', '56', '57', '58', '59', '6010', '6012', '6013', '6014', '6015', '6016', '6017', '6018', '6019', '602', '603', '604', '605', '6060', '616788', '62183', '62186', '62188', '62198', '62199', '6220', '622110', '627089', '62709601', '6271', '6272', '6273', '6274', '6275', '6276', '6277', '6278', '6279', '6280', '6281', '6294', '6301', '630490', '633857', '63609', '6361', '636392', '636708', '637043', '637102', '637118', '637187', '637529', '639', '640', '641', '642', '643', '670', '671', '672', '673', '674', '675', '677', '6760', '6761', '6762', '6763', '6764', '6765', '6766', '6768', '6769', '6771', '679'
                    ]]
                ],
                'options' => ['brand_name' => 'Maestro'],
            ],
            'electron' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => ['4026', '417500', '4405', '4508', '4844', '4913', '4917']]
                ],
                'options' => ['brand_name' => 'Visa Electron'],
            ],
            'unionpay' => [
                'rules' => [
                    ['length' => [16, 17, 18, 19], 'prefixes' => [
                        '620', '6210', '6212', '6213', '6214', '6215', '6216', '6217', '621977', '622126', '622127', '622128', '622129',
                        '62213', '62214', '62215', '62216', '62217', '62218', '62220', '62221', '62222', '62223', '62224', '62225',
                        '62226', '62227', '62228', '62229', '6223', '6224', '6225', '6226', '6227', '6228', '6229', '623', '624',
                        '625', '626', '62702', '62704', '62706', '62707', '6282', '6283', '6284', '6291', '6292', '632062', '685800',
                        '69075'
                    ]]
                ],
                'options' => ['brand_name' => 'China UnionPay', 'skip_luhn' => true],
            ],
            'discover' => [
                'rules' => [
                    ['length' => [16, 19], 'prefixes' => [
                        '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'
                    ]]
                ],
                'options' => ['brand_name' => 'Discover'],
            ],
            'rupay' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => [
                        '6061', '6062', '6063', '6064', '6065', '6066', '6067', '6068', '6069', '607', '608'
                    ]]
                ],
                'options' => ['brand_name' => 'RuPay', 'skip_luhn' => true],
            ],
            'hipercard' => [
                'rules' => [
                    ['length' => [19], 'prefixes' => [
                        '384100', '384140', '384160', '606282', '637095', '637568', '637599', '637609', '637612'
                    ]]
                ],
                'options' => ['brand_name' => 'Hipercard'],
            ],
            'elo' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => [
                        '401178', '401179', '431274', '438935', '451416', '457393', '457631', '457632', '504175', '506699', '50670', '50671',
                        '506717', '506718', '50672', '506720', '506721', '506724', '506725', '506726', '506727', '506728', '506729', '50673',
                        '50674', '50675', '50676', '506770', '506771', '506772', '506773', '506774', '506775', '506776', '506777', '506778',
                        '50900', '509013', '50902', '509031', '509033', '509035', '509036', '509037', '509038', '509039', '50904', '509050',
                        '509051', '509052', '509053', '509064', '509066', '509067', '509068', '509069', '509072', '509074', '509076', '509077',
                        '509078', '509079', '509080', '509081', '509082', '509083', '509085', '636297', '636368', '650031', '650032', '650033',
                        '650035', '650036', '650037', '650038', '650039', '65004', '650050', '650051', '650405', '650406', '650407', '650408',
                        '650409', '65041', '65042', '65043', '650485', '650486', '650487', '650488', '650489', '65049', '65050', '65051', '65052',
                        '650530', '650531', '650532', '650533', '650534', '650535', '650536', '650537', '650538', '650541', '650700', '650720',
                        '650901', '650921', '650922', '650923', '650924', '650925', '650926', '650927', '650928', '650929', '65093', '65094',
                        '65095', '65096', '650970', '650971', '650972', '650973', '650974', '650975', '650976', '650977', '650978', '651652',
                        '65500', '65501', '655021', '65503', '65504'
                    ]]
                ],
                'options' => ['brand_name' => 'Elo'],
            ],
            'mir' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => [
                        '2200', '2201', '2202', '2203', '2204'
                    ]]
                ],
                'options' => ['brand_name' => 'Mir'],
            ],
            'dankort' => [
                'rules' => [
                    ['length' => [16], 'prefixes' => ['5019']]
                ],
                'options' => ['brand_name' => 'Dankort'],
            ],
            'switch' => [
                'rules' => [
                    ['length' => [16, 18, 19], 'prefixes' => [
                        '4903', '4905', '4911', '4936', '564182', '633110', '6333', '6759'
                    ]]
                ],
                'options' => ['brand_name' => 'Switch'],
            ]            
            
        ];

        foreach ($cardTypes as $type => $data) {
            foreach ($data['rules'] as $rule) {
                if (in_array(strlen($cardNumber), $rule['length'])) {
                    foreach ($rule['prefixes'] as $prefix) {
                        if (strpos($cardNumber, $prefix) === 0) {
                            return isset($data['options']['brand_name']) ? $data['options']['brand_name'] : null;
                        }
                    }
                }
            }
        }

        return 'Unknown';
    }

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文