Regex credit card number tests
Asked Answered
P

16

79

I'm testing one application where Regex pattern match credit card then such numbers should be highlighted. I'm using site http://regexpal.com/ to create test credit credit card numbers for my testing. my requirement is to have valid credit card numbers which can have "-" and/or "," between them.I was not successful to build such a number as when i test it using the site

http://regexpal.com.

I need few credit numbers with scenarios below

  1. valid credit card number which can have "-" between any digit.
  2. valid credit card number which can have "," between any digit.
  3. valid credit card number which can have cobination of "," or "-" between any digit.
Propositus answered 16/2, 2012 at 17:5 Comment(3)
What language are you writing this in? Depending on the language it might be easier to do a remove using find and replace for - and , before validating with regex.Marybelle
This is related to java script as the site uses RegexPal 0.1.4 — a JavaScript regular expression testerPropositus
you can refer this regex tutorial - youtube.com/watch?v=M1iFcFUn3qwContextual
R
88

Remove all , and - and other non-digits from the string first.

Then use this regex that matches Visa, MasterCard, American Express, Diners Club, Discover, and JCB cards:

^(?: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})$

Rickyrico answered 16/2, 2012 at 17:8 Comment(7)
You might consider amending your answer to include a valid regular expression for credit cards, which you can find here: regular-expressions.info/creditcard.htmlMarybelle
what if credit card number is not continuous e.g 4111111111111111 and i put it in 4111 1111 1111 1111 way? this gives error.Contrabassoon
@Contrabassoon remove non-numeric characters from the input before validating.Ha
@Contrabassoon Non-numeric values are always ignored.Hackamore
This will need to be updated soon to handle Master Cards BIN addition of 2. mastercard.us/en-us/issuers/get-support/…Unroll
MasterCard will be adding 222100-272099 on 2016-10-14. So this will no longer catch all of their cards if I read this correctly.Judicature
I believe that you'd need to use [25][1-7][0-9]{14} for new MC numbersShew
D
242

Common credit card vendor regular expressions:

  • Amex Card: ^3[47][0-9]{13}$
  • BCGlobal: ^(6541|6556)[0-9]{12}$
  • Carte Blanche Card: ^389[0-9]{11}$
  • Diners Club Card: ^3(?:0[0-5]|[68][0-9])[0-9]{11}$
  • Discover Card: ^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})$
  • Insta Payment Card: ^63[7-9][0-9]{13}$
  • JCB Card: ^(?:2131|1800|35\d{3})\d{11}$
  • KoreanLocalCard: ^9[0-9]{15}$
  • Laser Card: ^(6304|6706|6709|6771)[0-9]{12,15}$
  • Maestro Card: ^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$
  • Mastercard: ^(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}))$
  • Solo Card: ^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$
  • Switch Card: ^(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}$
  • Union Pay Card: ^(62[0-9]{14,17})$
  • Visa Card: ^4[0-9]{12}(?:[0-9]{3})?$
  • Visa Master Card: ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$
Dextrality answered 22/4, 2014 at 22:21 Comment(10)
Formatted your answer as a list, I would alphabetize this list, but I will let you decide.Version
how to allow spaces and hyphens in these regex?Cataplasia
Worth noting that as of 2016-10-14 the MasterCard regex here will be insufficient as they will be adding a new range of 222100-272099. I just added the following for our validation: ^(?:5[1-5][0-9]\d{1}|222[1-9]|2[3-6][0-9]\d{1}|27[01][0-9]|2720)([\ \-]?)\d{4}\1\d{4}\1\d{4}$Judicature
Note that Visa Master Card matches Visa or MasterCard and isn't itself a card type.Broeker
Just a friendly warning, you're in for a world of hurt if you try and match specific schemes and card lengths this way. For example, Switch hasn't existed since 2002, Laser was withdrawn in 2014, Visa are due to issue 19 digit cards and MasterCard are now issuing in the 2xxxxx ranges, just to highlight a couple of issues with this approach. A regex is good for a basic "does it look like a card number" but not much beyond that.Gallicanism
Anyone have the regex for Apple Card?Blume
Can we have regex for EnRoute Cards ?Malinowski
Here's this answer, formatted as JavaScript code https://mcmap.net/q/259912/-regex-credit-card-number-tests (disclaimer: I wrote the answer)Thundercloud
Apple ^413491\d{10}$ and enroute ^\d{15}$Cammi
0000 0000 0000 0000 How can we fix the above code in the form of a space between 4 digits?Immensity
R
88

Remove all , and - and other non-digits from the string first.

Then use this regex that matches Visa, MasterCard, American Express, Diners Club, Discover, and JCB cards:

^(?: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})$

Rickyrico answered 16/2, 2012 at 17:8 Comment(7)
You might consider amending your answer to include a valid regular expression for credit cards, which you can find here: regular-expressions.info/creditcard.htmlMarybelle
what if credit card number is not continuous e.g 4111111111111111 and i put it in 4111 1111 1111 1111 way? this gives error.Contrabassoon
@Contrabassoon remove non-numeric characters from the input before validating.Ha
@Contrabassoon Non-numeric values are always ignored.Hackamore
This will need to be updated soon to handle Master Cards BIN addition of 2. mastercard.us/en-us/issuers/get-support/…Unroll
MasterCard will be adding 222100-272099 on 2016-10-14. So this will no longer catch all of their cards if I read this correctly.Judicature
I believe that you'd need to use [25][1-7][0-9]{14} for new MC numbersShew
M
28

2019

DO. NOT. USE. REGEX !!! (with 3 exclamation marks)


From the comments, I must highlight PeteWiFi's comment:

Just a friendly warning, you're in for a world of hurt if you try and match specific schemes and card lengths this way. For example, Switch hasn't existed since 2002, Laser was withdrawn in 2014, Visa are due to issue 19 digit cards and MasterCard are now issuing in the 2xxxxx ranges, just to highlight a couple of issues with this approach. A regex is good for a basic "does it look like a card number" but not much beyond that.

If you want to use regex just to know the card brand for visual use (like displaying Visa logo or label), that is fine. But if your code logic depends on it, then don't use regex, and don't use 3rd party plugin/library!

Regex detecting card numbers is quick & easy. But in the long run, your project will run into many serious & hard-to-solve bugs. Card issuers keep introducing new card number patterns, or withdraw old ones, or may completely close down. Who knows.


Solution

Build your own solution (preferably non-regex) based on some official pages that's frequently updated, like this page on wikipedia.

As for the "-", ".", "space", and all other noise, simply remove all these non-digits, you can use this (Based on this answer):

$number = preg_replace("/[^0-9]/", "", "4111-1111 1111.1111");
// Output: 4111111111111111

Not convinced yet?

This page goes into deep technical details why regex is hell. (Notice the artical used the word "hell" because once you're in you can't go out)

EDIT

Here's a solution I developed (in 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;
}
Matsumoto answered 6/3, 2019 at 9:26 Comment(5)
I agree that validation shall contain not only a pattern matching, but also involve validating of the check digit as pointed out in Wikipedia. Readability and maintenance of the regexes are also problematic on the long run.Stuff
I know that it's quite old as answer, but (at least in js) you should use the following regexp pattern to consider the dot too: /[\D.]/Nev
This is the correct solution. Using RegEx and updating them is a nightmare.Hudnut
The funny fact is you started with DO. NOT. USE. REGEX !!! (with 3 exclamation marks) but then we see regexes in your code. Anyway, the correct way of using complex regex is generating it by class/function which keeps validation logic and returns a regex which is useful. This way regex is easy to update, because you update the code that generates it.Urochrome
@SławomirLenart You read just 1st line & PHP solution (probably you skipped 1st/2nd paragraphs). I use regex all the time, but not for detecting card numbers.Matsumoto
S
11

The accepted answer is great, but to accommodate the new MasterCard BIN, I believe that it would need to be updated to:

^(?: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})$

(the critical piece being [25][1-7][0-9]{14}, since the first digit can now be either a 2 or a 5 and the second digit can be up to 7)

Please correct me if I'm wrong!

Shew answered 29/3, 2017 at 20:32 Comment(0)
R
8

For Rupay Debit Card: ^6[0-9]{15}$

Rouse answered 6/1, 2016 at 12:30 Comment(1)
@trimul-rao Can you please get this checked? This wasn't working for my Rupay Card.Lamar
P
6

Here is my method for detecting card network (updated 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";
    }
Piddle answered 2/6, 2020 at 9:34 Comment(3)
MAESTRO regex is missing the delimiters and there is no $ in the DISCOVER pattern, is it intended?Frost
It must return VISA, just remove "minus" symbolsPiddle
wow, your MAESTRO regex matches 5080741549588144562433243243243243241Periscope
R
4

Regex for Leading Card Networks

Master Card(2-Bin, 5-Bin both):"(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}"

Visa: "^4[0-9]{6,}$"

Diner's Club: "(^30[0-5][0-9]{11}$)|(^(36|38)[0-9]{12}$)"

American Express: "^[34|37][0-9]{14}$"

JCB: "(^3[0-9]{15}$)|(^(2131|1800)[0-9]{11}$)"

Discover: "^6011-?\d{4}-?\d{4}-?\d{4}$"

Rombert answered 23/11, 2017 at 8:36 Comment(2)
Hello, I have a question on your American Express regular expression: I know that an amex card has 15 digits and it's starting either with 34 or 37, your regular expression is matching a string starting either with 34 or with 37 THEN 14 digits, doesn't it sum to 16? I tested it in Rubular and it is working, can you please tell me if I'm wrong in my reasoning?Dissolution
@Dissolution [34|37] is wrong, as [] is used for classes of characters in any regex engine, this will NOT match 34 or 37, this will match either 3 or 4 or | or 7. The correct syntax would have been (34|37) here the | is indeed alternation and the parenthesis just delimit where the options start and stop.Dioptometer
S
3

In addition to all above, here's a regex for new MasterCards, that includes 2221-2720 BINs:

^5[1-5][0-9]{0,14}|^(222[1-9]|2[3-6]\\d{2}|27[0-1]\\d|2720)[0-9]{0,12}

Note, this regex will match if user starts typing card digits, that correspond to MasterCard. For example, if user types "222185" then the regex will match, because there is no other type of card that starts with "2221". This regex might come handy if you want to display card type while typing first digits of the card.

Alternatively, if you want "post factum" matching, you can change the last part from {0,14} and {0,12} to {14} and {12}:

^5[1-5][0-9]{14}|^(222[1-9]|2[3-6]\\d{2}|27[0-1]\\d|2720)[0-9]{12}
Savdeep answered 18/4, 2018 at 9:9 Comment(8)
5[1-5][0-9]{0,15} should be 5[1-5][0-9]{0,14} and if you want an exact match it should be {14} in the bottom pattern in addition to {12} on the end.Motorway
@Savdeep - What if the card number is 5555 5555 5555 4444, will this work?Obellia
@Neel, yes it will. 5[1-5][0-9]{14} this part of regex will match your input.Savdeep
It is not matching, may you please try? @Savdeep - regex101.comObellia
@Neel, have you removed all whitespaces from string before matching? Perform matching with 5555555555554444, not with 5555 5555 5555 4444.Savdeep
Okay that was my question, will this work with 5555 5555 5555 4444? My use case is to match with or without white space @SavdeepObellia
None of regexes you see in provided answers will match any card number with whitespace.Savdeep
@Obellia The spaces in card numbers are for human eyes. Practically all implementations I've ever seen strip out all non-digits before matching or processing the card.Motorway
H
2

I came up with a regex that allows for dashes and spaces. Test it here: https://regex101.com/r/Rx2iWD/1

To allow commas (which I think is unusual), just add it to the sep definition.

In PHP:

$ccPatt = '/
    (?(DEFINE)
        (?<sep> [ -]?)
    )
    (?<!\d)(?:
      \d{4} (?&sep) \d{4} (?&sep) \d{4} (?&sep) \d{4}               # 16 digits
    | \d{3} (?&sep) \d{3} (?&sep) \d{3} (?&sep) \d (?&sep) \d{3}    # 13 digits
    | \d{4} (?&sep) \d{6} (?&sep) \d{4}                             # 14 digits
    | \d{4} (?&sep) \d{6} (?&sep) \d{5}                             # 15 digit card
    )(?!\d)
/xu';
Hearsh answered 10/11, 2016 at 23:20 Comment(0)
H
2

For anyone trying to do this with Swift (iOS), I built a little project that doesn't use RegEx that does CC prefix validation, check digit validation (using Luhn algorithm), and a few other cool things. It is very simple to modify to add new card types and number ranges without having to know complex RegEx. It's similar to what @evilReiko does in his answer.

100% free. Full open source.

https://github.com/ethanwa/credit-card-scanner-and-validator

Hudnut answered 20/3, 2021 at 8:11 Comment(0)
P
1

Regx for Rupay card :

(508[5-9][0-9]{12})|(6069[8-9][0-9]{11})|(607[0-8][0-9]{12})|(6079[0-8][0-9]{11})|(608[0-5][0-9]{12})|(6521[5-9][0-9]{11})|(652[2-9][0-9]{12})|(6530[0-9]{12})|(6531[0-4][0-9]{11})

using bin series : 508500 – 508999, 606985 – 606999, 607000 - 607899, 607900 - 607984, 608001 -- 608500, 652150 --- 652199, 652200 --- 652999, 653000 --- 653099, 653100 --- 653149,

Picofarad answered 10/2, 2016 at 9:52 Comment(0)
W
1

Regex for all card type

^(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}))$

Check can here https://regex101.com/r/37S1iV/1

Wesleywesleyan answered 29/4, 2021 at 11:13 Comment(0)
D
0

First Data validates 15 digits for Amex and 16 for visa, mc, discover, diners, and jcb so I only send the card number to them if the number is 15 or 16 digits long using this:

^[0-9]{15}(?:[0-9]{1})?$
Dietetics answered 14/9, 2017 at 17:4 Comment(0)
T
0

Here's this answer formatted as JavaScript code.

  let card_types = {
    "Amex Card": /^3[47][0-9]{13}$/,
    "BCGlobal": /^(6541|6556)[0-9]{12}$/,
    "Carte Blanche Card": /^389[0-9]{11}$/,
    "Diners Club Card": /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
    "Discover Card": /^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})$/,
    "Insta Payment Card": /^63[7-9][0-9]{13}$/,
    "JCB Card": /^(?:2131|1800|35\d{3})\d{11}$/,
    "KoreanLocalCard": /^9[0-9]{15}$/,
    "Laser Card": /^(6304|6706|6709|6771)[0-9]{12,15}$/,
    "Maestro Card": /^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$/,
    "Mastercard":/ ^(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}))$/,
    "Solo Card": /^(6334|6767)[0-9]{12}|(6334|6767)[0-9]{14}|(6334|6767)[0-9]{15}$/,
    "Switch Card": /^(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}$/,
    "Union Pay Card": /^(62[0-9]{14,17})$/,
    "Visa Card": /^4[0-9]{12}(?:[0-9]{3})?$/,
    "Visa Master Card": /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$/,
  };
Thundercloud answered 22/8, 2022 at 6:52 Comment(0)
R
0

For the multiple requests in the comments asking for a solution to whitespace separated values, this can be achieved pretty easily:

\b(\d{4}\s\d{4}\s\d{4}\s\d{4}$)\b
Rhett answered 21/2, 2023 at 1:14 Comment(0)
P
0

evilReiko solution in javascript

var 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'],
},
'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'],
},
'visa': {
    '4': ['13-19'],
}
};


var get_card_brand = function(cardNumber, validateLength = true)
{
cardNumber      = (cardNumber || "").toString().replace(new RegExp("[-.\\s]", "gmi"), "").trim();

if(/[0-9]/.test(cardNumber.substr(0,1)))
{
    cardNumber = cardNumber.replace(new RegExp("[^0-9]", "gmi"), "0").padEnd(6, "0");

    var firstSixDigits   = parseInt(cardNumber.substr(0, 6));
    var cardNumberLength = cardNumber.length;

    for(var brand in CARD_NUMBERS)
    {
        for(var prefix in CARD_NUMBERS[brand])
        {
            var lengths = CARD_NUMBERS[brand][prefix];

            var prefixArray = prefix.split("-");

            var prefixMin = parseInt(prefixArray[0].padEnd(6, "0"));
            var prefixMax = parseInt((prefixArray[1] || prefixArray[0]).padEnd(6, "9"));

            var isValidPrefix = firstSixDigits >= prefixMin && firstSixDigits <= prefixMax;

            if(isValidPrefix && !validateLength)
            {
                return brand;
            }


            if(isValidPrefix && validateLength)
            {
                for(var i = 0; i < lengths.length; i++)
                {
                    var length = lengths[i];
                    var isValidLength = false;

                    var lengthArray = length.split("-");

                    var minLength = parseInt(lengthArray[0]);
                    var maxLength = parseInt(lengthArray[1] || lengthArray[0]);

                    var isValidLength = cardNumberLength >= minLength && cardNumberLength <= maxLength;

                    if(isValidLength)
                    {
                        return brand;
                    }
                }
            }
        }
    }
}

return "";
}


console.log(get_card_brand('4111111111111111') == "visa");                    // Output: "visa"
console.log(get_card_brand('4111.1111 1111-1111') == "visa");                 // Output: "visa" function will remove following noises: dot, space and dash
console.log(get_card_brand('411111######1111') == "visa");                    // Output: "visa" function can handle hashed card numbers
console.log(get_card_brand('41') == "");                                  // Output: "" because invalid length
console.log(get_card_brand('41', false) == "visa");                           // Output: "visa" because we told function to not validate length
console.log(get_card_brand('987', false) == "");                          // Output: "" no match found
console.log(get_card_brand('4111 1111 1111 1111 1111 1111') == "");       // Output: "" no match found
console.log(get_card_brand('4111 1111 1111 1111 1111 1111', false) == "visa");// Output: "visa" because we told fu**/
Phobia answered 17/5 at 10:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.