【问题标题】:Partially mask data of a group of number using regex使用正则表达式部分屏蔽一组数字的数据
【发布时间】:2021-10-05 02:34:15
【问题描述】:

我想使用正则表达式部分屏蔽数据。这是输入:

123-12345-1234567

这是我想要的输出:

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

我知道如何替换最后一组,但我不知道如何替换其余数据。

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

另外,我只想使用正则表达式,因为我有不同类型的数据,所以不同类型的掩码。我不想为每种类型的数据创建函数。

例如:

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

12334567 // becomes 123******

感谢您的帮助!

【问题讨论】:

  • 您可以简单地将索引i 处的字符更改为数组[1,2,4,5,6,7,8,10,11,12,13,14] 中每个索引的星号。
  • @CarySwoveland Java 中的字符串是不可变的,所以我们不能真正做到这一点。
  • @Tim,如何创建一个新字符串,其第 i 个字符是原始字符串中的第 i 个字符或星号,这取决于索引是否在我的第一条评论中的数组中?
  • Java 在优美简洁的字符串操作语法方面可能比 Ruby 或 Python 低很多。
  • @zozonenete 您应该检测模式的类型并通过映射器在类型到替换的正则表达式之间替换每种类型

标签: java regex


【解决方案1】:

我们可以使用以下正则表达式替换方法:

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

这里我们将第一个数字连接在一起,然后是中间部分,所有数字都替换为*,以及最后两个数字。

编辑:纯正则表达式解决方案,但是,它的代码行数比上面的多,并且性能可能较低。

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
}

【讨论】:

  • 有没有办法只用一个replaceAll,不带子字符串?
  • 我不知道。在其他语言中,例如 Python,我们可以使用正则表达式回调函数来避免子字符串操作。 Java 并没有这个功能。
  • 问题是我只想使用正则表达式,因为我有不同类型的数据,我不想为每种类型的数据创建不同的函数。例如,AAAAA 将变为 AA***
  • @zozonenete 我给了你正则表达式选项。我发现它比我给出的子字符串版本更难看。您决定使用哪一个。
【解决方案2】:

Java 支持后视中的固定量词,因此如果您必须仅使用正则表达式,您可以使用带有交替的模式来解释不同的场景。

使用环视,您可以选择要替换为 * 的单个字符

注意,这很难维护,使用单独的模式或字符串函数(可能伴随单元测试)为不同的数据格式编写单独的函数是一个更好的选择

(?<=^\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})?)

单独的部分匹配:

  • (?&lt;=^\d{3,7})\d(?=\d*$) 匹配一个断言左边有 3-7 位数字且只有右边数字的数字
  • |或者
  • (?&lt;=^[A-Z]{0,6})[A-Z](?=[A-Z]*$) 匹配 A-Z 断言左边有 0-6 个字符,右边只有 A-Z 字符
  • |或者
  • \d(?&lt;=^\d{2,3})(?=\d?-\d{5}-\d{7}$) 匹配一个断言左边 2-3 位数字和可选数字的数字, - 5 位数字和 - 7 位数字在右边
  • |或者
  • \d(?&lt;=^\d{3}-\d{1,5}(?:-\d{1,5})?) 匹配一个在左边断言 3 位数字的数字 - 和 1-5 位数字,以及可选 - 1-5 位数字

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, "*"));

输出

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

【讨论】:

    【解决方案3】:
    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,}).", "*"));
    }
    

    输出:

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

    【讨论】:

      猜你喜欢
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      相关资源
      最近更新 更多