use*_*784 43 regex regex-greedy
我正在测试一个Regex模式匹配信用卡的应用程序,然后突出显示这些数字.我正在使用网站http://regexpal.com/为我的测试创建测试信用卡信用卡号码.我的要求是拥有有效的信用卡号码,它们之间可以有" - "和/或",".我没有成功建立这样的数字,就像我使用网站测试它一样
下面的方案我需要很少的信用卡号码
aji*_*ban 163
普通信用卡供应商正则表达式:
^3[47][0-9]{13}$^(6541|6556)[0-9]{12}$^389[0-9]{11}$^3(?:0[0-5]|[68][0-9])[0-9]{11}$^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})$^63[7-9][0-9]{13}$^(?:2131|1800|35\d{3})\d{11}$^9[0-9]{15}$^(6304|6706|6709|6771)[0-9]{12,15}$^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$^(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}))$^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$^(4903|4905|4911|4936|6333|6759)[0-9]{12}|(4903|4905|4911|4936|6333|6759)[0-9]{14}|(4903|4905|4911|4936|6333|6759)[0-9]{15}|564182[0-9]{10}|564182[0-9]{12}|564182[0-9]{13}|633110[0-9]{10}|633110[0-9]{12}|633110[0-9]{13}$^(62[0-9]{14,17})$^4[0-9]{12}(?:[0-9]{3})?$^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$Ale*_*lov 53
首先从字符串中删除所有,和-其他非数字.
然后使用与Visa,MasterCard,American Express,Diners Club,Discover和JCB卡相匹配的正则表达式:
^(?:4[0-9]{12}(?:[0-9]{3})?|[25][1-7][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$
接受的答案很棒,但为了适应新的万事达卡BIN,我认为需要更新到:
^(?:4[0-9]{12}(?:[0-9]{3})?|[25][1-7][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$
(关键部分是[25][1-7][0-9]{14},因为第一个数字现在可以是2或5,第二个数字最多可以是7)
如果我错了请纠正我!
做。不。使用。正则表达式!(带有3个感叹号)
从评论中,我必须强调PeteWiFi的评论:
只是一个友好的警告,如果您尝试以这种方式匹配特定的方案和卡长度,那么您将遭受很多伤害。例如,自2002年以来Switch就不存在了,Laser在2014年退出了,Visa将发行19位数字卡,而MasterCard现在正在发行2xxxxx范围,仅强调了这种方法的几个问题。正则表达式对于基本的“看起来像卡号”很有用,但仅此而已。
如果您想使用正则表达式只是为了了解视觉使用的卡片品牌(显示Visa徽标或标签),那很好。但是,如果您的代码逻辑依赖于此,则不要使用正则表达式,也不要使用第三方插件/库!
正则表达式检测卡号快速简便(我知道,这很吸引人!)。但是,从长远来看,您的项目将遇到许多严重且难以解决的错误。发卡机构不断推出新的卡号模式,或撤回旧的卡号模式,或可能完全关闭。谁知道。
根据一些经常更新的官方页面来构建您自己的解决方案(最好是非正则表达式),例如Wikipedia上的此页面。
至于“-”,“。”,“空格”和所有其他噪声,只需除去所有这些非数字,就可以使用它(基于此答案):
$number = preg_replace("/[^0-9]/", "", "4111-1111 1111.1111");
// Output: 4111111111111111
Run Code Online (Sandbox Code Playgroud)
还没说服?
此页面深入探讨了正则表达式为何会导致地狱的技术细节。(请注意,艺术品使用了“地狱”一词,因为一旦进入,便无法外出)
这是我开发(使用PHP)的解决方案:
// Based on https://en.wikipedia.org/wiki/Payment_card_number
// This constant is used in get_card_brand()
// Note: We're not using regex anymore, with this approach way we can easily read/write/change bin series in this array for future changes
// Key (string) brand, keep it unique in the array
// Value (array) for each element in the array:
// Key (string) prefix of card number, minimum 1 digit maximum 6 digits per prefix. You can use "dash" for range. Example: "34" card number starts with 34. Range Example: "34-36" (which means first 6 digits starts with 340000-369999) card number starts with 34, 35 or 36
// Value (array of strings) valid length of card number. You can set multiple ones. You can also use "dash" for range. Example: "16" means length must be 16 digits. Range Example: "15-17" length must be 15, 16 or 17. Multiple values example: ["12", "15-17"] card number can be 12 or 15 or 16 or 17 digits
define('CARD_NUMBERS', [
'american_express' => [
'34' => ['15'],
'37' => ['15'],
],
'diners_club' => [
'36' => ['14-19'],
'300-305' => ['16-19'],
'3095' => ['16-19'],
'38-39' => ['16-19'],
],
'jcb' => [
'3528-3589' => ['16-19'],
],
'discover' => [
'6011' => ['16-19'],
'622126-622925' => ['16-19'],
'624000-626999' => ['16-19'],
'628200-628899' => ['16-19'],
'64' => ['16-19'],
'65' => ['16-19'],
],
'dankort' => [
'5019' => ['16'],
//'4571' => ['16'],// Co-branded with Visa, so it should appear as Visa
],
'maestro' => [
'6759' => ['12-19'],
'676770' => ['12-19'],
'676774' => ['12-19'],
'50' => ['12-19'],
'56-69' => ['12-19'],
],
'mastercard' => [
'2221-2720' => ['16'],
'51-55' => ['16'],
],
'unionpay' => [
'81' => ['16'],// Treated as Discover cards on Discover network
],
'visa' => [
'4' => ['13-19'],// Including related/partner brands: Dankort, Electron, etc. Note: majority of Visa cards are 16 digits, few old Visa cards may have 13 digits, and Visa is introducing 19 digits cards
],
]);
/**
* Pass card number and it will return brand if found
* Examples:
* get_card_brand('4111111111111111'); // Output: "visa"
* get_card_brand('4111.1111 1111-1111'); // Output: "visa" function will remove following noises: dot, space and dash
* get_card_brand('411111######1111'); // Output: "visa" function can handle hashed card numbers
* get_card_brand('41'); // Output: "" because invalid length
* get_card_brand('41', false); // Output: "visa" because we told function to not validate length
* get_card_brand('987', false); // Output: "" no match found
* get_card_brand('4111 1111 1111 1111 1111 1111'); // Output: "" no match found
* get_card_brand('4111 1111 1111 1111 1111 1111', false);// Output: "visa" because we told function to not validate length
* Implementation Note: This function doesn't use regex, instead it compares digit by digit.
* Because we're not using regex in this function, it's easier to add/edit/delete new bin series to global constant CARD_NUMBERS
* Performance Note: This function is extremely fast, less than 0.0001 seconds
* @param String|Int $cardNumber (required) Card number to know its brand. Examples: 4111111111111111 or 4111 1111-1111.1111 or 411111###XXX1111
* @param Boolean $validateLength (optional) If true then will check length of the card which must be correct. If false then will not check length of the card. For example you can pass 41 with $validateLength = false still this function will return "visa" correctly
* @return String returns card brand if valid, otherwise returns empty string
*/
function get_card_brand($cardNumber, $validateLength = true) {
$foundCardBrand = '';
$cardNumber = (string)$cardNumber;
$cardNumber = str_replace(['-', ' ', '.'], '', $cardNumber);// Trim and remove noise
if(in_array(substr($cardNumber, 0, 1), ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])) {// Try to find card number only if first digit is a number, if not then there is no need to check
$cardNumber = preg_replace('/[^0-9]/', '0', $cardNumber);// Set all non-digits to zero, like "X" and "#" that maybe used to hide some digits
$cardNumber = str_pad($cardNumber, 6, '0', STR_PAD_RIGHT);// If $cardNumber passed is less than 6 digits, will append 0s on right to make it 6
$firstSixDigits = (int)substr($cardNumber, 0, 6);// Get first 6 digits
$cardNumberLength = strlen($cardNumber);// Total digits of the card
foreach(CARD_NUMBERS as $brand => $rows) {
foreach($rows as $prefix => $lengths) {
$prefix = (string)$prefix;
$prefixMin = 0;
$prefixMax = 0;
if(strpos($prefix, '-') !== false) {// If "dash" exist in prefix, then this is a range of prefixes
$prefixArray = explode('-', $prefix);
$prefixMin = (int)str_pad($prefixArray[0], 6, '0', STR_PAD_RIGHT);
$prefixMax = (int)str_pad($prefixArray[1], 6, '9', STR_PAD_RIGHT);
} else {// This is fixed prefix
$prefixMin = (int)str_pad($prefix, 6, '0', STR_PAD_RIGHT);
$prefixMax = (int)str_pad($prefix, 6, '9', STR_PAD_RIGHT);
}
$isValidPrefix = $firstSixDigits >= $prefixMin && $firstSixDigits <= $prefixMax;// Is string starts with the prefix
if($isValidPrefix && !$validateLength) {
$foundCardBrand = $brand;
break 2;// Break from both loops
}
if($isValidPrefix && $validateLength) {
foreach($lengths as $length) {
$isValidLength = false;
if(strpos($length, '-') !== false) {// If "dash" exist in length, then this is a range of lengths
$lengthArray = explode('-', $length);
$minLength = (int)$lengthArray[0];
$maxLength = (int)$lengthArray[1];
$isValidLength = $cardNumberLength >= $minLength && $cardNumberLength <= $maxLength;
} else {// This is fixed length
$isValidLength = $cardNumberLength == (int)$length;
}
if($isValidLength) {
$foundCardBrand = $brand;
break 3;// Break from all 3 loops
}
}
}
}
}
}
return $foundCardBrand;
}
Run Code Online (Sandbox Code Playgroud)
这是我检测卡网络的方法(2020年更新):
function getCardBrandId($pan)
{
$regs = [
ELECTRON => "/^(4026|417500|4405|4508|4844|4913|4917)\d+$/",
MAESTRO => "/^(?:50|5[6-9]|6[0-9])\d+$/",
DANKORT => "/^(5019|4571)\d+$/",
CUP => "/^(62|81)\d+$/",
VISA => "/^4[0-9]\d+$/",
DINERS => "/^(?:5[45]|36|30[0-5]|3095|3[8-9])\d+$/",
MC => "/^(?:5[1-5]|222[1-9]|22[3-9][0-9]|2[3-6][0-9][0-9]|27[0-1][0-9]|2720)\d+$/",
AMEX => "/^(34|37)\d+$/",
DISCOVER => "/^6(?:011|22(12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])|5|4|2[4-6][0-9]{3}|28[2-8][0-9]{2})\d+$/",
JCB => "/^(?:35[2-8][0-9])\d+$/",
INTERPAY => "/^(636)\d+$/",
KOREAN => "/^9[0-9]\d+$/",
MIR => "/^(?:220[0-4])\d+$/",
];
foreach ($regs as $brand => $reg) {
if (preg_match($reg, $pan)) {
return $brand;
}
}
return "Unknown";
}
Run Code Online (Sandbox Code Playgroud)