Eka T
Eka T

Reputation: 45

RegEx to find credit card pattern did not exclude the ones that has more than 16 digits

We are building a pattern matcher to find credit card pattern (not necessarily a valid one) from a string. Currently we are using this regex from regular-expressions.info

\b(?:\d[ -]*?){13,16}\b

The regex works fine for unless it's trying to exclude invalid numbers that are longer than 16 digits and has space or dash delimiter such as:

1234 5678 9001 0000 1111
1234-5678-9001-0000-1111
1234 5678 9001 00001 111
1234-5678-9001-00001-111

The RegEx will include some parts of the numbers and marked them as matched. Which is not what we expected. You can see it live at regex101.com

Can anyone help us?

Upvotes: 1

Views: 953

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626903

If you need to skip something and only get something else, it is easier to match what you want to skip and match and capture what you need to keep.

Use

\b(?:(?:\d[ -]*?){17,}|((?:\d[ -]*?){13,16}))\b

See the regex demo.

Details

  • \b - a word boundary
  • (?: - outer non-capturing group:
    • (?:\d[ -]*?){17,} - 17 or more digits optionally separated with 0+ spaces or -
    • | - or
    • ((?:\d[ -]*?){13,16}) - Group 1 matching 13 to 16 occurrences of a digit followed with 0+ spaces or/and hyphens
  • ) - end of the outer group to match the strings within word boundaries only
  • \b - a word boundary

C# code:

var values_we_need = Regex.Match(our_text, @"\b(?:(?:\d[ -]*?){17,}|((?:\d[ -]*?){13,16}))\b")
    .Cast<Match>()
    .Select(m => m.Groups[1].Value)
    .ToList();

Upvotes: 3

Thomas Ayoub
Thomas Ayoub

Reputation: 29431

Since it appears that your have a separator you can split the entry then test it over this regex ^(?:\d[ -]*?){13,16}$:

static void Main(String[] args)
{
    var myInput = "5000123456789001, 5000-1234-5678-9001, 5000 1234 5678 9001, 50001234567890010000, 5000-1234-5678-9001-0000, 5000 1234 5678 9001 0000, 5000-1234-5678-90010-000, 5000 1234 5678 90010 000";

    foreach (var cardNumber in SeparateInput(myInput, ','))
    {
        Console.WriteLine($"'{cardNumber}' is {(IsThisNumberValid(cardNumber) ? "valid" : "not valid" )}");
    }

    Console.ReadLine();
}

private static bool IsThisNumberValid(string input)
{
    return Regex.IsMatch(input, @"^(?:\d[ -]*?){13,16}$");
}

private static IEnumerable<string> SeparateInput(string input, char separator)
{
    foreach (var splitted in input.Split(new []{separator}, StringSplitOptions.RemoveEmptyEntries))
    {
        yield return splitted.Trim();
    }
}

Upvotes: 0

Related Questions