user10586382
user10586382

Reputation:

Partially mask data of a group of number using regex

I would like to partially mask data using regex. Here is the input :

123-12345-1234567

And here is what I'd like as output :

1**-*****-*****67

I figure out how to replace for the last group but I don't know to do for the rest of the data.

String s = "123-12345-1234567";
System.out.println(s.replaceAll("\\d(?=\\d{2})", "*")); // output is *23-***45-*****67

Also, I'd like to use only regex because I have different type of data, so different type of mask. I don't want to create functions for each type of data.

For example :

AAAAAAAAA // becomes ********AA

12334567 // becomes 123******

Thanks for your help !

Upvotes: 1

Views: 1077

Answers (3)

user4910279
user4910279

Reputation:

public static void main(String[] args) {
    System.out.println("123-12345-1234567".replaceAll("(?<=.{1,})\\d(?=.{3,})", "*"));
    System.out.println("AAAAAAAAA".replaceAll(".(?=.{2,})", "*"));
    System.out.println("12334567".replaceAll("(?<=.{3,}).", "*"));
}

output:

1**-*****-*****67
*******AA
123*****

Upvotes: 0

The fourth bird
The fourth bird

Reputation: 163362

Java supports a fixed quantifier in a lookbehind, so what you might do is use a pattern with an alternation to account for the different scenario's if you must use a regex only.

Using the lookarounds you can select a single character to be replaced by *

Note that this is hard to maintain, and it would be a better option to write separate functions for the different data formats using separate patterns or string functions (perhaps accompanied by unit tests)

(?<=^\d{3,7})\d(?=\d*$)|(?<=^[A-Z]{0,6})[A-Z](?=[A-Z]*$)|\d(?<=^\d{2,3})(?=\d?-\d{5}-\d{7}$)|\d(?<=^\d{3}-\d{1,5}(?:-\d{1,5})?)

The separate parts match:

  • (?<=^\d{3,7})\d(?=\d*$) Match a digit asserting 3-7 digits to the left and only digits to the right
  • | Or
  • (?<=^[A-Z]{0,6})[A-Z](?=[A-Z]*$) Match A-Z asserting 0-6 chars to the left and only chars A-Z to the right
  • | Or
  • \d(?<=^\d{2,3})(?=\d?-\d{5}-\d{7}$) Match a digit asserting 2-3 digits to the left and optional digit, - with 5 digits and - with 7 digits to the right
  • | Or
  • \d(?<=^\d{3}-\d{1,5}(?:-\d{1,5})?) Match a digit asserting 3 digits to the left followed - and 1-5 digits and optionally - with 1-5 digits

Regex demo | Java demo

String regex = "(?<=^\\d{3,7})\\d(?=\\d*$)|(?<=^[A-Z]{0,6})[A-Z](?=[A-Z]*$)|\\d(?<=^\\d{2,3})(?=\\d?-\\d{5}-\\d{7}$)|\\d(?<=^\\d{3}-\\d{1,5}(?:-\\d{1,5})?)";

String s1 = "123-12345-1234567";
String s2 = "AAAAAAAAA";
String s3 = "12334567";

System.out.println(s1.replaceAll(regex, "*"));
System.out.println(s2.replaceAll(regex, "*"));
System.out.println(s3.replaceAll(regex, "*"));

Output

1**-*****-*****67
*******AA
123*****

Upvotes: 0

Tim Biegeleisen
Tim Biegeleisen

Reputation: 521419

We can use the following regex replacement approach:

String input = "123-12345-1234567";
String output = input.substring(0, 1) +
                input.substring(1, input.length()-2).replaceAll("\\d", "*") +
                input.substring(input.length()-2);
System.out.println(output);  // 1**-*****-*****67

Here we concatenate together the first digit, followed by the middle portion with all digits replaced by *, along with the final two digits.

Edit: A pure regex solution, which, however, is more lines of code than the above and might be less performant.

String input = "123-12345-1234567";
String pattern = "^(\\d)(.*)(\\d{2})$";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(input);
if (m.find()) {
    String output = m.group(1) + m.group(2).replaceAll("\\d", "*") + m.group(3);
    System.out.println(output);  // 1**-*****-*****67
}

Upvotes: 1

Related Questions