我需要将字符串转换为某种形式的哈希。这在 JavaScript 中可能吗?
我没有使用服务器端语言,所以我不能那样做。
原文由 Freesnöw 发布,翻译遵循 CC BY-SA 4.0 许可协议
我需要将字符串转换为某种形式的哈希。这在 JavaScript 中可能吗?
我没有使用服务器端语言,所以我不能那样做。
原文由 Freesnöw 发布,翻译遵循 CC BY-SA 4.0 许可协议
这里的许多答案都是相同的 String.hashCode
取自 Java 的哈希函数。它可以追溯到 1981 年的 Gosling Emacs,非常弱,并且在现代 JavaScript 中的性能意义为零。事实上,使用 ES6 Math.imul
可以显着加快实现速度,但没有人注意到。我们可以做得更好,性能基本相同。
这是我做的一个 — cyrb53 ,一个简单但高质量的 53 位哈希。它非常快,提供非常好的*散列分布,并且因为它输出 53 位,所以与 任何 32 位散列相比,冲突率要低得多。此外,您可以忽略 SA 的 CC 许可证,因为它是 我 GitHub 上的公共域。
const cyrb53 = (str, seed = 0) => {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
};
console.log(`cyrb53('a') -> ${cyrb53('a')}`)
console.log(`cyrb53('b') -> ${cyrb53('b')}`)
console.log(`cyrb53('revenge') -> ${cyrb53('revenge')}`)
console.log(`cyrb53('revenue') -> ${cyrb53('revenue')}`)
console.log(`cyrb53('revenue', 1) -> ${cyrb53('revenue', 1)}`)
console.log(`cyrb53('revenue', 2) -> ${cyrb53('revenue', 2)}`)
console.log(`cyrb53('revenue', 3) -> ${cyrb53('revenue', 3)}`)
*大致类似于大家熟知的MurmurHash/xxHash算法。它使用乘法和 Xorshift 的组合来生成哈希,但不够彻底。因此,它比 JavaScript 中的任何一个都快,并且实现起来简单得多,但可能无法通过 SMHasher 中的所有测试。这不是加密哈希函数,因此请勿出于安全目的使用它。
像任何适当的散列一样,它具有雪崩效应,这基本上意味着输入中的小变化会导致输出中的大变化,从而使生成的散列看起来更“随机”:
"501c2ba782c97901" = cyrb53("a")
"459eda5bc254d2bf" = cyrb53("b")
"fbce64cc3b748385" = cyrb53("revenge")
"fb1d85148d13f93a" = cyrb53("revenue")
您可以选择为相同输入的备用流提供种子(无符号整数,最大 32 位):
"76fee5e6598ccd5c" = cyrb53("revenue", 1)
"1f672e2831253862" = cyrb53("revenue", 2)
"2b10de31708e6ab7" = cyrb53("revenue", 3)
从技术上讲,它是一个 64 位哈希,即并行计算的两个不相关的 32 位哈希,但 JavaScript 仅限于 53 位整数。如果方便,可以通过使用十六进制字符串或数组更改 返回语句 来使用完整的 64 位输出。
return [h2>>>0, h1>>>0];
// or
return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return 4294967296n * BigInt(h2) + BigInt(h1);
请注意,构建十六进制字符串会大大减慢批处理速度。该数组效率更高,但显然需要两次检查而不是一次检查。 I also included BigInt
, which should be slightly faster than String
, but still much slower than Array
or Number
.
只是为了好玩,这是 TinySimpleHash,这是我能想出的最小哈希值,但仍然不错。它是 89 个字符 的 32 位散列,具有比 FNV 或 DJB2 更好的质量随机性:
TSH=s=>{for(var i=0,h=9;i<s.length;)h=Math.imul(h^s.charCodeAt(i++),9**9);return h^h>>>9}
原文由 bryc 发布,翻译遵循 CC BY-SA 4.0 许可协议
10 回答11.1k 阅读
6 回答3k 阅读
5 回答4.8k 阅读✓ 已解决
4 回答3.1k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
3 回答2.3k 阅读✓ 已解决
3 回答2.1k 阅读✓ 已解决
资源:
http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/