Skip to content
d.devtul.fun
中文
Regex · Credit Card

Credit Card Regex

Patterns that recognize each card network by prefix and length, plus the rule that matters more: only Luhn proves a number is real.

The pattern

^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|2(?:22[1-9]|2[3-9][0-9]|[3-6][0-9]{2}|7[01][0-9]|720)[0-9]{12}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12}|62[0-9]{14})$

Matches the prefix and length ranges of major networks. It says nothing about whether the number is a real, issued card.

Test this pattern

Edit the text below — matching happens locally, nothing is uploaded.

Variants

Length only, any network
^[0-9]{13,19}$

A loose filter that just checks digit count. Useful as a first gate, useless for telling networks apart.

Visa only
^4[0-9]{12}(?:[0-9]{3})?$

Exactly the Visa branch pulled out on its own. Use when you only accept one network.

What this regex matches

The combined pattern recognizes the major networks by their prefix and length:

^(?:4[0-9]{12}(?:[0-9]{3})?
  | 5[1-5][0-9]{14}
  | 2(?:22[1-9]|2[3-9][0-9]|[3-6][0-9]{2}|7[01][0-9]|720)[0-9]{12}
  | 3[47][0-9]{13}
  | 6(?:011|5[0-9]{2})[0-9]{12}
  | 62[0-9]{14})$

Each alternative is one network. Read them as a routing table, not as one monolithic rule.

Card networks and their prefixes

The leading digits of a card number are the Issuer Identification Number (IIN), formerly called the Bank Identification Number (BIN). The first digit alone often hints at the network; longer prefixes pin it down. The regex above encodes these rules.

NetworkStarts withLengthNotes
Visa413 or 16 (19 now possible)The (?:[0-9]{3})? allows the 16-digit form plus the older 13-digit.
Mastercard51-55 and 2221-272016The 2-series range was added in 2016; old regexes miss it.
American Express34, 3715Shorter than the others; do not force 16 digits.
Discover6011, 6516Also covers some 64x ranges in practice.
UnionPay6216-19Mainland China; length varies.

Length ranges: 13 to 19 digits

Card numbers are not a fixed length. The ISO/IEC 7812 standard allows 13 to 19 digits, and different networks use different lengths: Amex is 15, Visa is typically 16 (but 13 and now 19 exist), UnionPay spans 16 to 19. A regex that hardcodes {16} will reject perfectly valid cards. The pattern above uses per-network lengths precisely so it does not.

Regex only proves shape, not validity

This is the point that saves you from a real bug: a regex can confirm a string starts with 4 and has the right length for Visa. It cannot confirm the number is a genuine, issued, working card. Prefix and length are public knowledge; anyone can type sixteen digits that fit the pattern.

The property that actually separates a plausible number from a valid one is the check digit, computed by the Luhn algorithm. That is arithmetic, not pattern matching, and a regex cannot do it.

The Luhn algorithm

Luhn is a simple checksum. From the rightmost digit (the check digit), double every second digit; if doubling yields two digits, subtract 9 (or add the digits). Sum everything. A valid number makes the total a multiple of 10.

def luhn_ok(num):
    digits = [int(ch) for ch in num if ch.isdigit()]
    if not digits:
        return False
    total = 0
    parity = len(digits) % 2
    for i, d in enumerate(digits):
        if i % 2 == parity:
            d *= 2
            if d > 9:
                d -= 9
        total += d
    return total % 10 == 0

Pair this with a network regex: the regex tells you the network and expected length, Luhn tells you the check digit is correct. Together they catch typos and random guesses; neither alone does.

Common mistakes

WrongProblemRight
^4\d{15}$ for VisaMisses 13- and 19-digit Visa cards.^4[0-9]{12}(?:[0-9]{3})?$
One regex for all networks, no LuhnPasses any 16 digits that look right.Regex for network + Luhn check.
Ignoring Mastercard 2-series2221-2720 cards rejected.Include the 2-series branch.
Forcing 16 digits for AmexAll Amex (15 digits) rejected.Use per-network length.
Implementing Luhn as a regexImpossible; Luhn needs arithmetic.Use real code, not pattern.

Security: handle real numbers with care

Card numbers are sensitive. A few non-negotiable rules:

  • Do not validate real cards in untrusted front-end code you do not control; client-side checks are for UX, never for trust.
  • Never log full card numbers. Log at most the last four digits, if anything.
  • Do not store PANs unless you are PCI DSS compliant. The safest card data is the data you never touch — use a payment processor's tokenization instead of handling raw numbers.
  • Test with published test numbers (Visa 4111 1111 1111 1111, Mastercard 5500 0000 0000 0004, Amex 3782 822463 10005) and never run real cards through test builds.

Test numbers you can safely use

During development you need card-shaped data without touching real cards. The networks publish fixed test numbers that pass format and Luhn checks but are rejected by live authorization. Beyond the Visa, Mastercard, and Amex examples above, common ones include Discover 6011 1111 1111 1117 and UnionPay-style 62-prefixed numbers. Hard-code these in tests, never randomize them, and keep them out of any build that could reach a real processor. Running them in continuous integration gives you stable coverage of every network and length branch without ever moving real money.

When a regex is enough

Use the network regex for what it is good at: formatting the input as the user types, picking the correct card brand icon, and routing to the right processor. Use Luhn to reject obvious typos before you ever call a payment API. Everything beyond "looks plausible" belongs to the processor and the issuer, not your regex.

Frequently asked

Is a regex enough to validate a credit card?

No. Regex checks prefix and length only. The Luhn check digit, computed in code, is what proves the number is well-formed.

Why does my Visa regex reject some cards?

You probably hardcoded 16 digits. Visa also has 13- and 19-digit forms; use 4[0-9]{12}(?:[0-9]{3})?.

Can a regex implement the Luhn algorithm?

No. Luhn is arithmetic over the digits. You need real code, not a pattern.

Is it safe to validate cards in the browser?

For UX only. Never trust client-side checks, never log full numbers, and test with published test card numbers.

Related regex guides

Open the full Regex Tester