Подтвердить что ты не робот

Проверка номеров кредитных карт Regex

Я тестирую одно приложение, в котором шаблон Regex соответствует кредитной карте, тогда такие числа должны быть выделены. Я использую сайт http://regexpal.com/ для создания тестовых кредитных кредитных карт для моего тестирования. мое требование состоит в том, чтобы иметь действительные номера кредитных карт, которые могут иметь "-" и/или "" между ними. Мне не удалось создать такой номер, как при проверке его с помощью сайта

http://regexpal.com.

Мне нужно немного номеров кредитов со сценариями ниже

  • действительный номер кредитной карты, который может иметь "-" между любыми цифрами.
  • действительный номер кредитной карты, который может иметь "," между любыми цифрами.
  • действительный номер кредитной карты, который может иметь привязку "," или "-" между любыми цифрами.
4b9b3361

Ответ 1

Удалите все , и - и другие нецифровые символы из первой строки.

Затем используйте это регулярное выражение, которое соответствует картам 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})$

Ответ 2

Обычные регулярные выражения поставщиков кредитных карт:

  • Карта Amex: ^3[47][0-9]{13}$
  • BCGlobal: ^(6541|6556)[0-9]{12}$
  • Карта Карт Бланш: ^389[0-9]{11}$
  • Карта Diners Club: ^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})$
  • Платежная карта Insta: ^63[7-9][0-9]{13}$
  • Карта JCB: ^(?:2131|1800|35\d{3})\d{11}$
  • KoreanLocalCard: ^9[0-9]{15}$
  • Лазерная карта: ^(6304|6706|6709|6771)[0-9]{12,15}$
  • Карта Маэстро: ^(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}))$
  • Карта соло: ^(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}$
  • Union Pay Card: ^(62[0-9]{14,17})$
  • Карта Visa: ^4[0-9]{12}(?:[0-9]{3})?$
  • Visa Master Card: ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})$

Ответ 3

Для дебетовой карты Rupay: ^6[0-9]{15}$

Ответ 4

Принятый ответ замечательный, но для размещения новой MasterCard 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)

Пожалуйста, поправьте меня, если я ошибаюсь!

Ответ 5

2019

ДЕЛАТЬ. НЕ. ИСПОЛЬЗОВАНИЕ. REGEX !!! (с 3 восклицательными знаками)


Из комментариев я должен выделить PeteWiFi комментарий:

Просто дружеское предупреждение, если вы попытаетесь подобрать конкретные схемы и длины карт таким образом. Например, свитч не существует с 2002 года, лазер был отозван в 2014 году, срок действия визы выпускать 19-разрядные карты, и MasterCard теперь выпускаются в 2xxxxx диапазоны, просто чтобы выделить пару проблем с этим подходом. регулярное выражение хорошо для базового "это похоже на номер карты", но не намного выше этого.

Если вы хотите использовать регулярные выражения просто для того, чтобы узнать марку карты для визуального использования (отображать логотип или этикетку Visa), это нормально. Но если от этого зависит ваша логика кода, не используйте регулярные выражения и не используйте сторонние плагины/библиотеки!

Regex обнаруживает номера карт быстро & легко (так привлекательно, я знаю!). Но в конечном итоге ваш проект столкнется со многими серьезными проблемами. трудно решаемые ошибки. Эмитенты карт продолжают вводить новые шаблоны номеров карт, либо отменяют старые, либо могут полностью закрыться. Кто знает.


Решение

Создайте свое собственное решение (желательно без регулярных выражений) на основе некоторых официальных страниц, которые часто обновляются, например, на этой странице в Википедии.

Что касается "-", ".", "Пробел" и всех других шумов, просто удалите все эти нецифровые символы, вы можете использовать это (на основе этого ответа answer):

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

Еще не убеждены?

На этой странице подробно рассматриваются технические причины, по которым регулярные выражения являются адом. (Notice the artical used the word "hell" because once you're in you can't go out)

. (Обратите внимание, что в художественном тексте использовалось слово "ад", потому что, как только вы оказались внутри, вы не можете выйти)EDIT

Вот решение, которое я разработал (на 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 does not use regex, instead it compares digit by digit. 
 *                      Because we're not using regex in this function, it 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;
}

Ответ 6

Regx для карты Rupay:

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

с использованием серии bin: 508500 - 508999, 606985 - 606999, 607000 - 607899, 607900 - 607984, 608001 - 608500, 652150 --- 652199, 652200 --- 652999, 653000 --- 653099, 653100 --- 653149,

Ответ 7

В дополнение ко всему вышесказанному, здесь приведено регулярное выражение для новых карт MasterCard, включающее 2221-2720 БИН:

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

Обратите внимание, что это регулярное выражение будет соответствовать, если пользователь начнет вводить цифры карты, соответствующие MasterCard. Например, если пользователь введет "222185", регулярное выражение будет соответствовать, потому что нет другого типа карты, которая начинается с "2221". Это регулярное выражение может пригодиться, если вы хотите отобразить тип карты при вводе первых цифр карты.

В качестве альтернативы, если вы хотите сопоставить "постфактум", вы можете изменить последнюю часть с {0,14} и {0,12} на {14} и {12}:

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

Ответ 8

Я придумал регулярное выражение, которое позволяет использовать тире и пробелы. Протестируйте его здесь: https://regex101.com/r/Rx2iWD/1

Чтобы разрешить запятые (что, как мне кажется, необычно), просто добавьте его в определение sep.

В 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';

Ответ 9

Первые данные подтверждают наличие 15 цифр для Amex и 16 для получения визы, mc, find, diners и jcb, поэтому я отправляю только номер карты, если это число составляет 15 или 16 цифр, используя это:

^[0-9]{15}(?:[0-9]{1})?$

Ответ 10

Regex для ведущих карточных сетей

Master Card (2-биновый, 5-биновый): "(?: 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 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} $)"

Откройте: "^ 6011 -?\d {4} -?\d {4} -?\d {4} $"