algorithm - 基于数字,你如何检测信用卡的类型?

  显示原文与译文双语对照的内容

我想知道如何根据信用卡号码来检测信用卡类型。 谁知道有一个确定的可靠的方法来找到这个?

时间:

贷方/借方卡号码被称为一个平移或者主帐号 。 前六位数字的这个锅是取自 IIN 或者颁发者识别码,属于开证行( IINs以前被称为—银行标识号 —,因此你可以在一些文档中看到对该术语的引用) 。 在这六位数字不受一种国际标准,number, iso/iec 7812,和可以用于确定该类型的卡。

在维基百科上,不幸的是实际的ISO/IEC 7812数据库是不会公开的,然而有非官方的列表,包括商业和自由,包括

不管怎么样,来检测该类型从下面的数字处理,可以使用一个正则表达式类似的那些: 的原始表达式的贷记

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

万事达信用卡:^5[1-5][0-9]{5,}$ 万事达信用卡的数字是以这些数值通过 55,51但这种方法只能检测万事达信用卡 ;还有其他卡的发行使用文中提供的万事达信用卡系统应用于不属于IIN范围内。

34或者美国运通:^3[47][0-9]{5,}$ 美国运通信用卡号码 start.

俱乐部:^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ Diners俱乐部卡号码以 300到 305,36或者 38开始。 有Diners俱乐部卡,以 5开始,有 16个数字。 这些是Diners俱乐部和MasterCard之间的合资企业,应该像信用卡一样处理。

发现:^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开始。

不幸的是有许多纸牌类型处理与万事达信用卡系统不活在IIN的万事达信用卡的范围( 正在启动 51的数字。。55 ) ;最重要的后果是,从其他银行的大师卡片,其中许多已经发行在外的'IIN范围所以,位于所有数字上的空间。 因此,任何卡那不是某其他类型的广告,最好就假设你接受必须是万事达

重要: 卡号确实会改变长度;例如签证都有过去颁发的卡,包括 13位全景和卡,包括 16位烤盘上。 12之间和 19 digits,档当前表示它可以签发的签证,或者可能已经颁发 numbers. 至少 7数字 的长度,因此,你不应检查卡的号码,以验证它以外的有。

之前先在输入,一个进一步提示:处理一个持卡人谈到,带任何空格和标点 characters. 正面的一个实际的信用卡,为什么,因为它通常是成群多少更易于键入数字号码,类似于何种方式显示的选项?


4444 4444 4444 4444

输入要容易得多,要比

 
4444444444444444

 

你不要指望在这儿chastising用户中实际上没有好处,因为他们输入了字符

这个也意味着使确保你的输入字段有室 至少 24字符,否则用户如果输入空格就能移动空间不足。 于expansion,相关我建议你来将字段设置足够的宽度来显示 32 headroom.的人提供对足够的字符,支持多达 64 ;

下面是一个更直观的图像:

在评论中在这里 answer, 更新( 2014 ):校验和方法似乎不再是一个有效的方法一种真实性的验证卡作为 noted.

Credit Card Verification

试试这个:

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":"/^4d{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;
}

在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|35d{3})d{11}$/
 };
 if (re.electron.test(number)) {
 return 'ELECTRON';
 } else if (re.maestro.test(number)) {
 return 'MAESTRO';
 } else if (re.dankort.test(number)) {
 return 'DANKORT';
 } else if (re.interpayment.test(number)) {
 return 'INTERPAYMENT';
 } else if (re.unionpay.test(number)) {
 return 'UNIONPAY';
 } else if (re.visa.test(number)) {
 return 'VISA';
 } else if (re.mastercard.test(number)) {
 return 'MASTERCARD';
 } else if (re.amex.test(number)) {
 return 'AMEX';
 } else if (re.diners.test(number)) {
 return 'DINERS';
 } else if (re.discover.test(number)) {
 return 'DISCOVER';
 } else if (re.jcb.test(number)) {
 return 'JCB';
 } else {
 return undefined;
 }
}

单元测试:


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

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

他们都使用旅馆范围来检测类型。 在这里你可以阅读有关旅馆

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

所以对于大多数用过的卡片我们都有下一个规则


######## 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 algoritm ( 它是descibed这里 http://en.wikipedia.org/wiki/Luhn ) 。

下面是的完整 C# 或者VB代码,用于所有在codeproject上的相关内容。

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

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


 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|35d{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#

下面是一个php类函数返回由 CCnumber CCtype 。
这里代码不验证卡或者未运行Luhn算法只尝试在中查找基于表的信用卡类型这里页面 。 basicly使用CCnumber长度和CCcard前缀来确定CCcard类型。


 <?php class CreditcardType
 {
 public static $creditcardTypes = array(
 array('Name'=>'American Express','cardLength'=>array(15),'cardPrefix'=>array('34', '37'))
, array('Name'=>'Maestro','cardLength'=>array(12, 13, 14, 15, 16, 17, 18, 19),'cardPrefix'=>array('5018', '5020', '5038', '6304', '6759', '6761', '6763'))
, array('Name'=>'Mastercard','cardLength'=>array(16),'cardPrefix'=>array('51', '52', '53', '54', '55'))
, array('Name'=>'Visa','cardLength'=>array(13,16),'cardPrefix'=>array('4'))
, array('Name'=>'JCB','cardLength'=>array(16),'cardPrefix'=>array('3528', '3529', '353', '354', '355', '356', '357', '358'))
, array('Name'=>'Discover','cardLength'=>array(16),'cardPrefix'=>array('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'))
, array('Name'=>'Solo','cardLength'=>array(16, 18, 19),'cardPrefix'=>array('6334', '6767'))
, array('Name'=>'Unionpay','cardLength'=>array(16, 17, 18, 19),'cardPrefix'=>array('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'))
, array('Name'=>'Diners Club','cardLength'=>array(14),'cardPrefix'=>array('300', '301', '302', '303', '304', '305', '36'))
, array('Name'=>'Diners Club US','cardLength'=>array(16),'cardPrefix'=>array('54', '55'))
, array('Name'=>'Diners Club Carte Blanche','cardLength'=>array(14),'cardPrefix'=>array('300','305'))
, array('Name'=>'Laser','cardLength'=>array(16, 17, 18, 19),'cardPrefix'=>array('6304', '6706', '6771', '6709'))
 ); 
 private function __construct() {} 
 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;
 }
 }?>

压缩的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|35d{3})d{11}$/
 };
 for (var card in cards) {
 if (cards[card].test(number)) {
 return card;
 }
 }
 };

不要试图检测信用卡类型作为处理付款的一部分。 你正在风险降低有效事务。

如果你需要向付款处理器提供信息( 例如。 PayPal信用卡对象需要命名卡类型,然后从可用的信息中猜测它,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.');
}

这里实现( 只使用前两位数字) 足以识别所有主要的( 如果是 paypal,所有支持的) 卡方案。 事实上,你可能希望完全跳过例外,并默认为最流行的卡类型。 让支付网关/处理器告诉你是否有验证错误,响应你的请求。

事实是你的支付网关不关心你提供的

信用卡的第一个号码可以用来近似供应商:

  • 签证:49,44或者 47
  • 签证电子:42,45,48,49
  • 万事达卡:51
  • Amex:34
  • 食客:30,36,38
  • JCB: 35
...