猿问

从多个输入字符串生成确定性唯一固定长度文件名字符串

我有多个字符串,我想用它们来生成一个单一的、固定长度的、确定性的字符串。我试图确保数据库中的唯一性,并且还将使用字符串作为文件名;所以我需要尽可能避免冲突,并需要避免特殊字符。我还需要它是确定性的,以便相同顺序的相同三个字符串将产生相同的输出字符串。


我想在已知的分隔符和 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;

    }

}

与此方法发生冲突的几率是多少?从多个输入字符串生成适合文件名的确定性固定长度字符串的最佳方法是什么?当然不是这样。


牛魔王的故事
浏览 257回答 2
2回答

猛跑小猪

我真的不明白,是什么阻碍了你像你已经做的那样只使用哈希函数?它们旨在完成您想要实现的目标(前提是我说对了)。您可以简单地连接字符串,应用散列函数并存储散列。碰撞当然是可能的,但是当试图将无限空间映射到有限空间时,情况总是如此。

慕标琳琳

我现在想出的解决方案是:protected String parseHash() {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; MessageDigest digest = MessageDigest.getInstance("SHA-512");&nbsp; &nbsp; &nbsp; &nbsp; List<String> strings = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; strings.add("one");&nbsp; &nbsp; &nbsp; &nbsp; strings.add("two");&nbsp; &nbsp; &nbsp; &nbsp; strings.add("three");&nbsp; &nbsp; &nbsp; &nbsp; strings.removeIf(str -> str == null || str.isEmpty());&nbsp; &nbsp; &nbsp; &nbsp; for(int i = 0; i < strings.size(); i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String string = strings.get(i);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string = string.replace("|", "\\|");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; strings.set(i, string);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; String input = String.join("|", strings);&nbsp; &nbsp; &nbsp; &nbsp; byte[] hash = digest.digest(input.getBytes());&nbsp; &nbsp; &nbsp; &nbsp; return DatatypeConverter.printHexBinary(hash);&nbsp; &nbsp; } catch(NoSuchAlgorithmException e) {&nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; }}正如我读过的那样,UUID.nameUUIDFromBytes(hash);将计算给定散列的 md5,这会降低散列的分辨率。使用散列的原始十六进制似乎是我能想到的最优雅的方式,但我当然愿意接受其他答案。
随时随地看视频慕课网APP

相关分类

Java
我要回答