题目描述
先给一个列表words,和一个日志信息的字符串,请对日志信息中的敏感信息进行屏蔽。
日志信息字符串是以,
分割的[key:value]格式表示的字符串,value中不会包括字符,
和:
,以key值区分衣服为敏感信息。
敏感信息:其key值有两类,第1类是出现在words中的,第2类是缺省关键字password
和pwd
(注:第2类优先)。
敏感信息屏蔽规则:
- key为
password
或pwd
的:对应的value统一用6个*
代替。 - key在words中,且以
IP
(不区分大小写)结尾的:对应value中ip地址中间两段分别用三个*
代替(不用考虑IPv6格式),用例保证IP格式的合法性。 - key在words中,且以非
IP
结尾的:仅需对value中最右侧的长度(L)大于等于4,且连续为数字的子串进行屏蔽,从倒数第L/4+1个数字字符开始(比如L为9,从倒数第三个开始),从右到左对中间的L/2个字符用*
代替。
非敏感信息处理规则: 原样输出。
注:关键字匹配时不区分大小写,输出时保持大小写不变。
解答要求
时间限制:1000ms,内存限制:256MB
输入
首行为一个正整数N,表示敏感信息关键字的个数,取值范围:[0, 50]。
第二行为一个长度为N的一维数组,表示敏感信息关键字列表words,每个关键字的长度范围:[0, 15]。
第三行为一个字符串,表示待处理的日志信息,字符串长度范围:[1, 200]。
输出
一个字符串,表示屏蔽后的日志信息。
样例
输入样例
5
IMSI CellID UserIP CID UID
Apn:cnet,Qos:121212121212,CellID:4600175319,Imsi:460019852146201,GWIP:1.1.1.1,UserIp:2.2.2.2,CID:854710-336985-852,UID:1-2-3-4,pwd:huawei7410
输出样例
Apn:cnet,Qos:121212121212,CellID:460*****19,Imsi:46001*******201,GWIP:1.1.1.1,UserIp:2.***.***.2,CID:854710-33***5-852,UID:1-2-3-4,pwd:******
编码实现(java)
public static void main(String[] args) {
String[] keys = new String[]{"IMSI", "CellID", "UserIP", "CID", "UID"};
String log = "Apn:cnet,Qos:121212121212,CellID:4600175319,Imsi:460019852146201,GWIP:1.1.1.1,UserIp:2.2.2.2,CID:854710-336985-852,UID:1-2-3-4,pwd:huawei7410";
System.out.println(logAnonymize(keys, log));
}
private static String logAnonymize(String[] keys, String log) {
// 敏感信息关键字转小写
List<String> words = Arrays.stream(keys).map(String::toLowerCase).collect(Collectors.toList());
String[] logEntries = log.split(",");
StringBuilder maskedLog = new StringBuilder();
for (String entry : logEntries) {
String[] keyValue = entry.split(":");
String key = keyValue[0].trim();
String value = keyValue[1].trim();
if (key.equalsIgnoreCase("password") || key.equalsIgnoreCase("pwd")) {
value = "******";
} else if (words.contains(key.toLowerCase())) {
if (key.toLowerCase().endsWith("ip")) {
String[] ipSegments = value.split("\\.");
if (ipSegments.length == 4) {
ipSegments[1] = "***";
ipSegments[2] = "***";
value = String.join(".", ipSegments);
}
} else {
int length = value.length();
int startIndex = -1; // 连续数字的子串末尾下标
int count = 0; // 连续数字的个数
for (int i = length - 1; i >= 0; i--) {
if (Character.isDigit(value.charAt(i))) { // 判断是否为数字
if (startIndex == -1) {
startIndex = i;
}
count++;
} else {
if (count >= 4) { // 为非数字时 判断当前子串是否满足条件
break;
} else {
startIndex = -1;
count = 0;
}
}
}
if (startIndex != -1 && count >= 4) {
// 从倒数L/4+1个数字字符开始 = startIndex-(L/4+1)+1 = startIndex - count / 4
int hideEndIndex = startIndex - count / 4;
// 屏蔽中间的L/2个字符 由于hideEndIndex本身也在屏蔽范围内 故hideStartIndex = hideEndIndex - count / 2 + 1
int hideStartIndex = hideEndIndex - count / 2 + 1;
StringBuilder stringBuilder = new StringBuilder(value);
for (int i = hideStartIndex; i <= hideEndIndex; i++) {
stringBuilder.setCharAt(i, '*');
}
value = stringBuilder.toString();
}
}
}
maskedLog.append(key).append(":").append(value).append(",");
}
String maskedLogString = maskedLog.toString();
if (maskedLogString.endsWith(",")) {
maskedLogString = maskedLogString.substring(0, maskedLogString.length() - 1);
}
return maskedLogString;
}
输出结果
Apn:cnet,Qos:121212121212,CellID:460*****19,Imsi:46001*******201,GWIP:1.1.1.1,UserIp:2.***.***.2,CID:854710-33***5-852,UID:1-2-3-4,pwd:******
Process finished with exit code 0