devkult_
tools29converters34
home/regex/credit-card

Regex for Credit Card Numbers

Card numbers are 13 to 19 digits, usually written in groups separated by spaces or hyphens. This pattern accepts that shape and nothing else. A regex can't tell whether a number is valid — follow it with the Luhn checksum — and avoid handling raw card numbers on your own servers at all.

/^(?:\d[ -]?){12,18}\d$/

How it works, token by token

TokenMeaning
^start of string
(?:\d[ -]?){12,18}12 to 18 digits, each optionally followed by one space or hyphen
\da final digit, so there's no trailing separator
$end of string

What it matches

✓4111 1111 1111 1111
✓5500-0000-0000-0004
✓340000000000009
✗4111 1111 1111
✗4111 1111 1111 1111
✗4111-1111-1111-111a

Try it live

One candidate per line — the m flag makes the ^ and $ anchors apply to each line. Edit anything; it runs in your browser.

/

Variations

^4\d{12}(?:\d{3}){0,2}$Visa: starts with 4; 13, 16 or 19 digits (separators removed)
^(?:5[1-5]\d{2}|2(?:22[1-9]|2[3-9]\d|[3-6]\d{2}|7[01]\d|720))\d{12}$Mastercard: 51–55 or 2221–2720, 16 digits

Language notes

  • Remove separators before checking brand prefixes or running Luhn — in JavaScript, value.replace(/[ -]/g, "").

Frequently asked questions

What is the Luhn check?

A checksum built into every card number: from the right, double every second digit, subtract 9 from any result over 9, and add everything up. Valid numbers total a multiple of 10. It catches typos, not fraud.

Should my server see card numbers at all?

Avoid it. Use your payment provider's hosted fields (such as Stripe Elements), so raw numbers go straight to the provider and most PCI DSS requirements stay off your plate.

Related patterns

Building something custom? The regex tester gives you live match highlighting for any pattern.