我想使用多个String来生成一个固定长度的确定性字符串。我正在尝试确保数据库中的唯一性,并且还将使用字符串作为文件名;因此,我将需要尽可能避免冲突,并避免使用特殊字符。我还需要确定性,以便相同顺序的相同三个字符串将产生相同的输出字符串。
我想到了将字符串连接到已知的定界符和base64编码上。但这不是固定长度。
我想到了串联字符串,从该字符串中获取哈希值,并对其进行base64编码。但是默认情况下,base64具有windoze会抱怨的特殊字符,这似乎是一种不好的做法。
现在我正在这样做,这也很难看:
protected UUID parseUUID() {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
List<String> strings = new ArrayList<>();
strings.add(stringOne);
strings.add(stringTwo);
strings.add(stringThree);
strings.removeIf(str -> str == null || str.isEmpty());
for(int i = 0; i < strings.size(); i++) {
String string = strings.get(i);
string = string.replace("|", "\\|");
strings.set(i, string);
}
String input = String.join("|", strings);
byte[] hash = digest.digest(input.getBytes());
return UUID.nameUUIDFromBytes(hash);
} catch(NoSuchAlgorithmException e) {
return null;
}
}
此方法的碰撞几率是多少?从多个输入字符串生成适合文件名的确定性固定长度字符串的最佳方法是什么?当然不是。
答案 0 :(得分:0)
我真的不明白,是什么阻碍了您像以前那样使用哈希函数?它们旨在完全按照您想要实现的目标(前提是我正确无误)。您可以简单地连接字符串,应用哈希函数并存储哈希。
冲突当然是可能的,但是在尝试将无限空间映射到有限空间时,总是如此。
答案 1 :(得分:0)
我现在想出的解决方案是:
protected String parseHash() {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
List<String> strings = new ArrayList<>();
strings.add("one");
strings.add("two");
strings.add("three");
strings.removeIf(str -> str == null || str.isEmpty());
for(int i = 0; i < strings.size(); i++) {
String string = strings.get(i);
string = string.replace("|", "\\|");
strings.set(i, string);
}
String input = String.join("|", strings);
byte[] hash = digest.digest(input.getBytes());
return DatatypeConverter.printHexBinary(hash);
} catch(NoSuchAlgorithmException e) {
return null;
}
}
当我读过UUID.nameUUIDFromBytes(hash);
时,将计算给定哈希值的md5,这会降低哈希值的解析度。使用哈希的原始十六进制似乎是我能想到的最优雅的方法,但是我当然可以接受其他答案。