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.