Masking credit card number using regex

You can use this regex with a lookahead and lookbehind:

str = str.replaceAll("(?<!^..).(?=.{3})", "*");
//=> **0**********351

RegEx Demo

RegEx Details:

  • (?<!^..): Negative lookahead to assert that we don't have 2 characters after start behind us (to exclude 3rd character from matching)
  • .: Match a character
  • (?=.{3}): Positive lookahead to assert that we have at least 3 characters ahead

I would suggest that regex isn't the only way to do this.

char[] m = new char[16];  // Or whatever length.
Arrays.fill(m, '*');
m[2] = cc.charAt(2);
m[13] = cc.charAt(13);
m[14] = cc.charAt(14);
m[15] = cc.charAt(15);
String masked = new String(m);

It might be more verbose, but it's a heck of a lot more readable (and debuggable) than a regex.


Here is another regular expression:

(?!(?:\D*\d){14}$|(?:\D*\d){1,3}$)\d

See the online demo

It may seem a bit unwieldy but since a credit card should have 16 digits I opted to use negative lookaheads to look for an x amount of non-digits followed by a digit.

  • (?! - Negative lookahead
    • (?: - Open 1st non capture group.
      • \D*\d - Match zero or more non-digits and a single digit.
      • ){14} - Close 1st non capture group and match it 14 times.
    • $ - End string ancor.
    • | - Alternation/OR.
    • (?: - Open 2nd non capture group.
      • \D*\d - Match zero or more non-digits and a single digit.
      • ){1,3} - Close 2nd non capture group and match it 1 to 3 times.
    • $ - End string ancor.
    • ) - Close negative lookahead.
  • \d - Match a single digit.

This would now mask any digit other than the third and last three regardless of their position (due to delimiters) in the formatted CC-number.

Tags:

Java

Regex