0

I am trying to write code that returns a credit card vendor using regular expression, which seem to work, eg:

// Visa - always begins digit 4, 13 or 16 digits long
^[4].{12}|^[4].{15} 

// Visa Electron - begin with the code pattern, 16 digits long
4026.{12}|417500.{10}|4405.{12}|4508.{12}|4844.{12}|4913.{12}|4917.{12}

So for a method isVisa I want the regex to say "return Visa based on the Visa regex, but not Visa Electron"

This code does not work:

    public static String isVisa(String number) {
    Pattern p = Pattern.compile("^[4].{12}|^[4].{15}&&(!4026.{12}|!417500.{10}|!4405.{12}|!4508.{12}|!4844.{12}|!4913.{12}|!4917.{12})");
    Matcher m = p.matcher(number);
    if (m.matches()) return "Visa";
    else return "";
}
NRKirby
  • 1,584
  • 4
  • 21
  • 38
  • FYI You need length 16-19 and Visa overlaps Eletcron in many ranges, to do this properly you need a regularly updated lookup table of BIN ranges (I was doing something similar last week) – Alex K. Jun 21 '14 at 15:29
  • Wouldn't the last line be better for `return m.matches() ? "Visa" : "";` – Unihedron Jun 21 '14 at 15:29
  • 1
    This seems like a boolean function to me. You might want to return a boolean here instead of a string – pwilmot Jun 21 '14 at 15:39

3 Answers3

1

The matches() method validates the regular expression against the entire string, so you do not need the start ^ and end $ anchors. Also the regular expression engine is matching these characters &! as literals, which it seems you are trying to use them as operators.

To ignore those patterns you can use a Negative Lookahead to achieve this.

(?!.*(?:(?:4026|4405|4508|4844|4913|4917).{12}|417500.{10}))(?=4.{12}|4.{15}).*

Example: This returns true for the first two since the rest are not valid for your case.

String[] numbers = { "4000236512341234", "4000222213232222", "4026122222222222", 
                     "4175000000000000", "4405343434344343", "4508111111111111",
                     "4844000000000000", "4913000000000000", "4917000000000000" };

Pattern p = Pattern.compile("(?!.*(?:(?:4026|4405|4508|4844|4913|4917).{12}|417500.{10}))(?=4.{12}|4.{15}).*");

for (String x: numbers) {
    Matcher m = p.matcher(x);
    System.out.println(m.matches());
}

Output:

true
true
false
false
false
false
false
false
false
hwnd
  • 69,796
  • 4
  • 95
  • 132
0

Use positive and negative lookaheads to check for the lines which starts with some numbers and doesn't starts with some specific numbers.

^(?!417500.{10}|4026.{12}|4405.{12}|4508.{12}|4844.{12}|4913.{12}|4917.{12})(?=4.{12}|4.{15}).*

DEMO

Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
0

You could use a very simple and easy to understand regex:

4026.{12}|417500.{10}|4405.{12}|4508.{12}|4844.{12}|4913.{12}|4917.{12}|([4].{12}|[4].{15})

This will match all the Visa Electron patterns without capturing anything. When you get a match, check capture group one isn't null for it to be Visa.

See this answer for a great explanation of the technique.

Community
  • 1
  • 1
RobEarl
  • 7,862
  • 6
  • 35
  • 50