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

591

我正在尝试仅根据信用卡号码来确定其类型。有没有人知道一种明确可靠的方法来找到它的类型?


4
使用正则表达式。请查看此链接以获取更多信息。 - senfo
3
所有细节都在维基百科上:http://en.wikipedia.org/wiki/Credit_card_numbers - Sten Vesterli
1
在维基百科上有一张很好的总结表,网址为http://en.wikipedia.org/wiki/Credit\_card_numbers。前六个数字指示了卡片的类型和发行者。 - Alex
3
除了提取第一个数字组之外,我不会使用正则表达式,通常只需要查看前4个数字(在美国)。另外,在费心清除费用之前,请对信用卡号运行Mod 10校验和以确保其合法性。[Luhn算法] (http://en.wikipedia.org/wiki/Luhn_algorithm) - Dan Blair
3
这些算法是否“永久有效”,还是会像“判断电话号码是否来自加州”的算法一样定期更改?请问有人能否对此发表评论? - Simon_Weaver
显示剩余4条评论
28个回答

882
信用/借记卡号称为主帐号(PAN),前六位来自发卡银行的发卡机构识别码(IIN),这六位数字遵循ISO/IEC 7812国际标准,可用于从号码中确定卡类型。遗憾的是,实际的ISO/IEC 7812数据库不公开,但有非官方列表,包括在维基百科上。无论如何,要从号码中检测出类型,可以使用以下类似的正则表达式:原始表达式的信用
Visa:^4[0-9]{6,}$ Visa卡号以4开头。

万事达卡: ^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年之前,万事达卡号码以51至55开头,但这只能检测到万事达信用卡;还有其他使用万事达卡系统发行的卡片不属于此IIN范围。在2016年,他们将添加范围内的数字(222100-272099)。

美国运通卡: ^3[47][0-9]{5,}$ 美国运通卡号码以34或37开头。

大来俱乐部卡: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ 大来俱乐部卡号码从300到305、36或38开始。也有以5开头且有16位数字的大来俱乐部卡。这些是大来俱乐部和万事达卡的合资企业,应像万事达卡一样处理。

Discover卡: ^6(?:011|5[0-9]{2})[0-9]{3,}$ Discover卡号码以6011或65开始。

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

不幸的是,有许多使用 MasterCard 系统处理的卡类型不在 MasterCard 的 IIN 范围内(以 51...55 开头的数字);最重要的情况是 Maestro 卡,其中许多卡是从其他银行的 IIN 范围发行的,因此分布在整个号码空间中。因此,最好假设任何不属于您接受的其他类型的卡都是 MasterCard 卡

重要提示:卡号长度确实有所不同;例如,Visa 曾经发行过具有 13 位 PAN 和 16 位 PAN 的卡。Visa 的文档目前表明,它可能已经或可能会发行介于 12 到 19 位之间的卡号。因此,您不应检查卡号的长度,除非验证其至少有 7 位数字(一个完整的 IIN 加上一个检查位数,应与 Luhn 算法 预测的值匹配)。

还有一个提示:在处理持卡人 PAN 之前,请从输入中删除任何空格和标点符号字符。为什么?因为通常可以更轻松地按组输入数字,类似于它们在实际信用卡的正面显示方式,即:

4444 4444 4444 4444

相对于正确输入来说,更简单。

4444444444444444

如果用户输入了你不希望看到的字符,责备他们并没有任何好处。

这也意味着要确保您的输入字段至少有24个字符的空间,否则输入空格的用户将会用完空间。我建议您将字段宽度设置为32个字符,并允许最多64个字符;这样可以提供足够的余地进行扩展。

以下是一张能更深入理解的图片:

更新(2016年): Mastercard将于Ach Payment实施新的BIN范围。

Credit Card Verification


8
很好的例子。你有Maestro卡的正则表达式吗? - Manikandan
7
不可以仅凭卡号长度来确定卡的类型,因为它们可能随时更改。您唯一可以依赖的是卡号的IIN(以前称为BIN),即卡号前缀。另外,不能按照您提出的方式检测万事达卡;这种方法只能检测到通过万事达系统处理的一部分卡片(主要问题是Maestro卡,其具有各种IIN前缀)。 - al45tair
4
@senfo 您是正确的,5412不会是完整的Mastercard卡号。 IIN(发行者标识号码)有六位数字,因此完整的卡号必须为7位数字(最少),并且必须通过Luhn校验。没有必要提供“证明”表明Mastercard卡号除16位数字外还有其他内容;重点是,无论今天的情况如何,在未来他们可能会发行17或18位数字的卡,或者也可能会发行一些15位数字的卡。依赖它们为16位数字长度是不必要的,并会产生长期维护风险。 - al45tair
4
我觉得很难相信,根据 Luhn 算法,一些有效的卡片会没有正确的校验位。这个算法被广泛用于检查卡号是否存在简单的输错或愚蠢的欺诈行为。相反,我发现有一些非常聪明的人只是不能理解这个算法,他们会计算错误。 - Rennex
4
@BaileyParker——LUHN算法不需要将数字除以10(或任何特定数字),它只是应用一个公式从数字中生成一个值,然后查看该值的最后一位数字(它使用%10而不是/10)。所有正在使用的卡片都使用它。 - RobG
显示剩余28条评论

96
在 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]);
            });
        });
    });
});

3
@jolly.exe - 你的小提琴返回所有测试的未定义值。不起作用 :( - ShadeTreeDeveloper
1
@ShadeTreeDeveloper 只需在文本字段中输入任何值,例如 AMAX 的 372176090165471。 - Code Spy
@jolly.exe 我明白了...我希望有一些东西可以在我输入时格式化(在keyup事件之外)。当我输入完整的数字时,这个小工具确实有效。 - ShadeTreeDeveloper
最终我写了这段代码来完成我想要的输入格式和验证。http://quercusv.github.io/smartForm/ - ShadeTreeDeveloper
你知道如何检测V-Pay和Bancontact卡号吗?谢谢。 - Oleksandr IY
似乎4508不属于Visa electron。 - igauravsehrawat

54

更新时间: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

Visa卡^4[0-9]{0,}$ 开头字符串:4

万事达卡^(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 开头的卡号必须被编码为万事达卡。Maestro卡必须在代码末尾被检测出来,因为其他几种卡也可能在 60 - 69 区间内。请查看代码。

Discover卡^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ Discover卡编码相当复杂,其开头字符串为 6011、622126-622925、644-649、65

Javascript中使用以下函数,将其分配给一个 onkeyup 事件,可以尽快获得结果。

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

    //JCB
    jcb_regex = new RegExp('^(?:2131|1800|35)[0-9]{0,}$'); //2131, 1800, 35 (3528-3589)
    // American Express
    amex_regex = new RegExp('^3[47][0-9]{0,}$'); //34, 37
    // Diners Club
    diners_regex = new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}$'); //300-305, 309, 36, 38-39
    // Visa
    visa_regex = new RegExp('^4[0-9]{0,}$'); //4
    // MasterCard
    mastercard_regex = new RegExp('^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$'); //2221-2720, 51-55
    maestro_regex = new RegExp('^(5[06789]|6)[0-9]{0,}$'); //always growing in the range: 60-69, started with / not something else, but starting 5 must be encoded as mastercard anyway
    //Discover
    discover_regex = new RegExp('^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$');
    ////6011, 622126-622925, 644-649, 65


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

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

    return sel_brand;
}

在这里你可以试玩它:

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

PHP用户请使用以下函数,该函数还可以检测一些子VISA/MC卡:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    }

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

1
请注意,这只是信用卡号码的检测,而不是验证。这应该是分开的,应该进行Luhn检查... - Janos Szabo
Visa Electron在哪里?为什么Maestro检查有时返回MasterCard?难道MasterCard不能自己检查吗? - BadHorsie
没有文档表明308或309开头的卡可以是JCB卡。 - Janos Szabo
+1 表示提供了 cc 类型检测代码,这通常是用于用户体验的 - MC 新范围的正则表达式需要进行微调: /^(5[1-5]|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{0,}$/ - kinakuta
似乎4508不属于Visa electron。 - igauravsehrawat
显示剩余2条评论

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

以下是使用正则表达式检查信用卡类型的C#函数:


21

看这个:

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

万事达卡已经升级,现在使用以2开头的数字等等。请更新你的代码。你可以使用这个正则表达式:*/^(?:5[1-5]|5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$/*。 - Nicholas Mberev

17

最近我需要这样的功能,我正在将Zend框架的信用卡验证器移植到Ruby中。 Ruby宝石:https://github.com/Fivell/credit_card_validations Zend框架:https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

它们都使用INN范围来检测信用卡类型。 在此处您可以阅读关于INN的信息:http://en.wikipedia.org/wiki/Bank_card_number

根据此,您可以替代地检测信用卡(而不使用正则表达式,而是声明一些有关前缀和可能长度的规则)

因此,我们为大多数常用卡制定了以下规则

########  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/Luhn)。

更新

更新的规则列表可以在此处找到:https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml


2
非常具有说明性。VISA卡可能有13位数字。 - Herman Kan
1
我认为这是遗留支持。 - Fivell
1
@HermanKan,还有一件事,VISA有VPay卡,根据维基百科的说法,Visa的VPay品牌可以指定13到19位数字的PAN长度,因此现在可以看到超过16位数字的卡号。 - Fivell
@Fivell RuPay的IIN/BIN是否已经正式发布在某个地方?据我所知,它正在增长,因此未来的更新可以从中获得良好的信息来源。(我尝试了谷歌搜索,但没有找到,如果您能分享您的信息源,我将不胜感激)。 - Ethan
1
@Ethan,请查看我更新的答案中的最后一个链接 https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml - Fivell
显示剩余3条评论

13

这里是CodeProject上的完整的C#或VB代码,用于各种与信用卡相关的功能

  • IsValidNumber(验证信用卡号码是否有效)
  • GetCardTypeFromNumber(从信用卡号码中获取信用卡类型)
  • GetCardTestNumber(获取用于测试的信用卡号码)
  • PassesLuhnTest(判断信用卡号码是否通过Luhn算法的检验)

本文已经发布了几年时间,没有任何负面评论。


1
@barett - 已修复。看起来他们将它从“aspnet”类别移动到“validation”类别,这改变了链接。 - Simon_Weaver
2
链接已经失效。也许这是同一个工具?http://www.codeproject.com/Articles/20271/Ultimate-NET-Credit-Card-Utility-Class - Josh Noe
那个 CodeProject 的代码是从 2007 年的。警告,它可能已经过时了。 - aron

9

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

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

8
在卡范围识别(CRR)中,使用一系列正则表达式或其他硬编码范围的算法的缺点是,在我看来,BINs/IINs会随着时间而变化。卡片联名是一个持续的复杂性。不同的卡收单商/商家可能需要您根据地理位置等因素以不同的方式处理相同的卡。
此外,在过去的几年里,例如银联卡在更广泛的流通,现有模型无法处理有时与它们取代的更广泛的范围交错的新范围。
了解系统需要覆盖的地理区域可能会有所帮助,因为某些范围仅限于特定国家/地区使用。例如,范围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的过关案例。

嗨@CaiqueOliveira,看到更新的链接了。感谢mac9416提供了更新的BIN-Rules参考链接。 - MikeRoger
1
感谢 @mac9416 提供更新的 BIN 规则参考。 - MikeRoger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接