Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Masking credit card number using regex

Tags:

java

regex

I am trying to mask the CC number, in a way that third character and last three characters are unmasked.

For eg.. 7108898787654351 to **0**********351

I have tried (?<=.{3}).(?=.*...). It unmasked last three characters. But it unmasks first three also.

Can you throw some pointers on how to unmask 3rd character alone?

like image 381
Sjvino User333 Avatar asked Jul 02 '20 16:07

Sjvino User333


People also ask

How do you mask card numbers?

Use 4 issuer digits. The first four digits of the credit card number are copied from the source to the output. The remaining part of the credit card number is appended with the masked account number and a check digit.

What is masked card pan?

PAN masking hides a portion of the long card number, or PAN, on a credit or debit card, protecting the card account numbers when displayed or printed.


Video Answer


5 Answers

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
like image 122
anubhava Avatar answered Nov 13 '22 19:11

anubhava


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.

like image 35
Andy Turner Avatar answered Nov 13 '22 17:11

Andy Turner


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.

like image 28
JvdV Avatar answered Nov 13 '22 17:11

JvdV


Apart from where the dashes are after the first 3 digits, leave the 3rd digit unmatched and make sure that where are always 3 digits at the end of the string:

(?<!^\d{2})\d(?=[\d-]*\d-?\d-?\d$)

Explanation

  • (?<! Negative lookbehind, assert what is on the left is not
    • ^\d{2} Match 2 digits from the start of the string
  • ) Close lookbehind
  • \d Match a digit
  • (?= Positive lookahead, assert what is on the right is
    • [\d-]* 0+ occurrences of either - or a digit
    • \d-?\d-?\d Match 3 digits with optional hyphens
  • $ End of string
  • ) Close lookahead

Regex demo | Java demo

Example code

String regex = "(?<!^\\d{2})\\d(?=[\\d-]*\\d-?\\d-?\\d$)";
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
String strings[] = { "7108898787654351", "7108-8987-8765-4351"};

for (String s : strings) {
    Matcher matcher = pattern.matcher(s);
    System.out.println(matcher.replaceAll("*"));
}

Output

**0**********351
**0*-****-****-*351
like image 38
The fourth bird Avatar answered Nov 13 '22 18:11

The fourth bird


Don't think you should use a regex to do what you want. You could use StringBuilder to create the required string

String str = "7108-8987-8765-4351";
StringBuilder sb = new StringBuilder("*".repeat(str.length()));

for (int i = 0; i < str.length(); i++) {
  if (i == 2 || i >= str.length() - 3) {
    sb.replace(i, i + 1, String.valueOf(str.charAt(i)));
  }
}

System.out.print(sb.toString());   // output: **0*************351
like image 32
Yousaf Avatar answered Nov 13 '22 18:11

Yousaf