题目描述

给你一条个人信息字符串 s,可能表示一个邮箱地址,也可能表示一串电话号码。按照以下规则对个人信息进行隐藏/加密处理:

邮箱地址规则

  • 所有字母转为小写。
  • 保留邮箱名的第一个字符和 @ 之前最后一个字符,中间用 "*****" 替换。
  • 域名保持不变。

举例:"LeetCode@LeetCode.com""l*****e@leetcode.com"

电话号码规则

  • 处理前 10-13 位数字的电话号码。
  • 手机号码格式为 "***-***-XXXX"(10 位)。
  • 带有国家代码时,国家代码的每一位用 "+" 开头,每一位用 "*" 代替(除最后一位外),如 11 位为 "+*-***-***-XXXX",12 位为 "+**-***-***-XXXX",13 位为 "+***-***-***-XXXX"
  • 输入可能包含 +-() 和空格等分隔符,需要先去除再做处理。

解题思路

本题的核心是区分输入是邮箱还是电话号码,然后分别处理。

第一步:识别类型

使用正则表达式区分输入类型:

  • 邮箱:包含 @ 符号,特点是以字母开头,格式为 name@domain.tld。不使用正则时,可以直接判断字符串是否包含 @;题目代码中使用正则 ^[a-zA-Z]+@[a-zA-Z]+\\.[a-zA-Z]+$ 来做更严格的匹配。
  • 电话号码:当不是邮箱时,匹配电话号码格式——包含 10-13 位数字,可能夹杂各种分隔符。正则 ^(?=(?:\\D*\\d){10,13}\\D*$)[+()\\s-]*\\d[\\d+()\\s-]*$ 用于验证是否为有效电话号码。

第二步:邮箱处理(maskEmail

  1. 将整个字符串转为小写。
  2. @ 分割得到用户名 name 和域名 domain
  3. 取用户名的第一个字符 + "*****" + 用户名的最后一个字符作为隐藏后的用户名。
  4. 拼接结果:隐藏后的用户名 + "@" + 域名

第三步:电话号码处理(maskPhone

  1. 使用 replaceAll 去除所有非数字字符(+-()、空格)。
  2. 提取最后 4 位数字作为 maskPhone(保留部分)。
  3. 根据电话号码的总长度(10、11、12、13 位)选择对应的掩码格式:
    • 10 位(如美国):"***-***-" + 后四位
    • 11 位(如中国+86):"+\*-***-***-" + 后四位(一位国家代码,用 * 隐藏)
    • 12 位:"+\*\*-***-***-" + 后四位(两位国家代码隐藏)
    • 13 位:"+\*\*\*-***-***-" + 后四位(三位国家代码隐藏)

复杂度分析

  • 时间复杂度O(n),其中 n 是输入字符串长度。正则匹配、字符串替换和拼接操作都只需线性扫描。
  • 空间复杂度O(n),需要存储处理后的字符串。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package code.J831;

import java.util.Locale;

public class J831 {
String emailSchema = "^[a-zA-Z]+@[a-zA-Z]+\\.[a-zA-Z]+$";
String phoneSchema = "^(?=(?:\\D*\\d){10,13}\\D*$)[+()\\s-]*\\d[\\d+()\\s-]*$";

public String maskPII(String s) {
if (s.matches(emailSchema)) return maskEmail(s);
if (s.matches(phoneSchema)) return maskPhone(s);
return s;
}

private String maskPhone(String s) {
String phone = s.replaceAll("[+\\-()\\s]", "");
int phoneLen = phone.length();
String maskPhone = phone.substring(phoneLen - 4, phoneLen);
return switch (phoneLen) {
case 10 -> "***-***-" + maskPhone;
case 11 -> "+*-***-***-" + maskPhone;
case 12 -> "+**-***-***-" + maskPhone;
case 13 -> "+***-***-***-" + maskPhone;
default -> s;
};
}

private String maskEmail(String s) {
StringBuilder sb = new StringBuilder();
String str = s.toLowerCase();
String name = str.split("@")[0];
String maskName = name.charAt(0) + "*****" + name.charAt(name.length() - 1);
sb.append(maskName);
sb.append("@");
sb.append(str.split("@")[1]);
return sb.toString();
}
}