And*_*son 504 language-agnostic algorithm e-commerce
我试图弄清楚如何根据其数量来检测信用卡的类型.有谁知道一个明确,可靠的方法来找到这个?
sen*_*nfo 743
信用卡/借记卡号码称为PAN或主帐号.PAN的前六位是取自IIN,或发行方识别号,属于开证行(不结盟研究所以前称为BIN -银行标识号-所以你可能会看到一些文件,这一术语引用).这六个数字符合国际标准ISO/IEC 7812,可用于从数字中确定卡的类型.
遗憾的是,实际的ISO/IEC 7812数据库不公开,但是有非商业和免费的非官方列表,包括维基百科.
无论如何,要从数字中检测类型,您可以使用如下所示的正则表达式:表示原始表达式
签证: ^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位数字.这些是大莱卡和万事达卡之间的合资企业,应该像万事达卡一样处理.
发现: ^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开始); 最重要的情况是Maestro卡,其中许多是从其他银行的IIN范围发行的,所以它们遍布数字空间.因此,最好假设您接受的任何其他类型的卡都必须是万事达卡.
重要提示:卡号的长度各不相同; 例如,Visa过去发行了13位数的PAN卡和16位数的PAN卡.Visa的文件目前表明它可能会发行或者可能发出12到19位数字. 因此,您不应检查卡号的长度,除了验证它至少有7位数(对于完整的IIN加一个校验位,它应该与Luhn算法预测的值相匹配).
进一步提示:在处理持卡人PAN之前,从输入中删除任何空格和标点字符.为什么?因为在组中输入数字通常要容易得多,类似于它们在实际信用卡的正面显示的方式,即
4444 4444 4444 4444
Run Code Online (Sandbox Code Playgroud)
比正确输入要容易得多
4444444444444444
Run Code Online (Sandbox Code Playgroud)
惩罚用户真的没有任何好处,因为他们输入了你没想到的字符.
这也意味着确保您的输入字段至少有 24个字符的空间,否则输入空格的用户将用完房间. 我建议你让字段宽到足以显示32个字符,最多允许64个字符; 这为扩展提供了充足的空间.
这是一个提供更多洞察力的图像:
更新(2014):校验和方法似乎不再是验证卡片真实性的有效方法,如本答案的评论中所述.
更新(2016年):万事达卡将实施新的BIN范围,从Ach付款开始.
Ana*_*liy 71
在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
}
}
}
Run Code Online (Sandbox Code Playgroud)
单元测试:
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]);
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
Jan*_*abo 34
更新时间:2016年6月15日(目前为最终解决方案)
请注意,我甚至投票支持最高投票,但为了明确这些正在实际工作的regexp我用数千个真正的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
万事达卡 ^(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.请看代码.
发现 ^(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
在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;
}
Run Code Online (Sandbox Code Playgroud)
在这里你可以玩它:
对于PHP使用此功能,它也会检测一些子VISA/MC卡:
/**
* Obtain a brand constant from a PAN
*
* @param type $pan Credit card number
* @param type $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
}
Run Code Online (Sandbox Code Playgroud)
Usm*_*nas 20
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";
}
Run Code Online (Sandbox Code Playgroud)
以下是使用Regex检查信用卡类型的功能,c#
Ras*_*shy 19
看一下这个:
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;
}
Run Code Online (Sandbox Code Playgroud)
Fiv*_*ell 14
最近我需要这样的功能,我正在将Zend Framework信用卡验证器移植到ruby.ruby gem:https://github.com/Fivell/credit_card_validations zend framework: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}
]
}
Run Code Online (Sandbox Code Playgroud)
然后通过搜索前缀和比较长度,您可以检测信用卡品牌.另外不要忘记luhn algoritm(这里有http://en.wikipedia.org/wiki/Luhn).
紧凑的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;
}
}
};
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个php类函数,由CCnumber返回CCtype.
此代码不验证卡或不运行Luhn算法只尝试根据此页面中的表查找信用卡类型.基本上使用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;
}
} ?>
Run Code Online (Sandbox Code Playgroud)
不要尝试检测信用卡类型作为处理付款的一部分.您有可能拒绝有效的交易.
如果您需要向支付处理器提供信息(例如,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.');
}
Run Code Online (Sandbox Code Playgroud)
这种实现(仅使用前两位数字)足以识别所有主要(在PayPal的情况下所有支持的)卡方案.实际上,您可能希望完全跳过该异常并默认为最常用的卡类型.让支付网关/处理器告诉您是否存在响应您的请求的验证错误.
实际情况是,您的支付网关并不关心您提供的价值.
在卡片范围识别(CRR)中,使用一系列正则表达式或其他硬编码范围的算法的缺点是BIN/IIN在我的经验中确实会随着时间的推移而发生变化.卡片的联合品牌是一个持续的复杂功能.不同的卡购买者/商家可能需要您以不同方式对待同一张卡,具体取决于例如地理位置.
此外,在过去几年中,例如银联卡在更广泛的流通中,现有的模型无法应对新的范围,有时会与更广泛的范围交错.
了解您的系统需要覆盖的地理位置可能有所帮助,因为某些范围仅限于在特定国家/地区使用.例如,范围62包括美国的一些AAA子范围,但如果您的商家基地位于美国境外,您可以将所有62个视为银联.
您可能还会被要求根据商家位置对卡进行不同的处理.例如,将某些英国卡片视为国内借记卡,但作为国际信用卡.
一个主要的收购银行维护着非常有用的规则.例如https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf和https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf.(截至2017年6月的有效链接,这要归功于提供更新参考链接的用户.)但请注意,虽然这些CRR规则可能代表发卡领域,因为它适用于该实体获得的商家,它不包括例如标识为CUP/UPI的范围.
这些注释适用于磁条(MagStripe)或PKE(Pan Key Entry)场景.ICC/EMV世界的情况再次不同.
更新:此页面上的其他答案(以及链接的WikiPedia页面)JCB始终为16长.然而,在我的公司,我们有一个专门的工程师团队,他们在多个收单银行和地区认证我们的POS设备和软件.这支团队从JCB获得的最新认证证书包含19个长PAN的通行证.
Swift 2.1版本的Usman Y的答案。使用打印语句进行验证,以便按某个字符串值进行调用
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 ""
}
Run Code Online (Sandbox Code Playgroud)