我需要将字符串转换为某种形式的哈希。这在JavaScript中可行吗?
我没有使用服务器端语言,所以我不能那样做。
我需要将字符串转换为某种形式的哈希。这在JavaScript中可行吗?
我没有使用服务器端语言,所以我不能那样做。
我没有使用服务器端语言,所以我不能那样做。
你肯定你不能这样做呀?
您是否忘了您正在使用Java语言(一种不断发展的语言)?
尝试SubtleCrypto
。它支持SHA-1,SHA-128,SHA-256和SHA-512哈希函数。
async function hash(message/*: string */) {
const text_encoder = new TextEncoder;
const data = text_encoder.encode(message);
const message_digest = await window.crypto.subtle.digest("SHA-512", data);
return message_digest;
} // -> ArrayBuffer
function in_hex(data/*: ArrayBuffer */) {
const octets = new Uint8Array(data);
const hex = [].map.call(octets, octet => octet.toString(16).padStart(2, "0")).join("");
return hex;
} // -> string
(async function demo() {
console.log(in_hex(await hash("Thanks for the magic.")));
})();
添加此代码是因为还没有人这样做,并且似乎需要使用散列方法来实现它,但是它总是做得很差。
这需要一个字符串输入,以及您希望哈希值等于的最大数字,并根据字符串输入生成一个唯一的数字。
您可以使用它来生成图像数组的唯一索引(如果您要为用户返回特定的化身,该化身是随机选择的,但也是根据其名称选择的,因此它将始终分配给具有该名称的人)。
当然,您也可以使用此方法将索引返回到颜色数组中,例如根据某人的名字生成唯一的头像背景颜色。
function hashInt (str, max = 1000) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash = hash & hash;
}
return Math.round(max * Math.abs(hash) / 2147483648);
}
@esmiralha的答案略有简化。
我不会在此版本中覆盖String,因为这可能会导致某些不良行为。
function hashCode(str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = ~~(((hash << 5) - hash) + str.charCodeAt(i));
}
return hash;
}
如果要避免冲突,则可能需要使用安全散列,例如SHA-256。有几种JavaScript SHA-256实现。
我编写了测试以比较几种哈希实现,请参阅https://github.com/brillout/test-javascript-hash-implementations。
或访问http://brillout.github.io/test-javascript-hash-implementations/来运行测试。
一种快速简洁的方法,从这里改编而成:
String.prototype.hashCode = function() {
var hash = 5381, i = this.length
while(i)
hash = (hash * 33) ^ this.charCodeAt(--i)
return hash >>> 0;
}
我基于FNV Multiply+Xor
方法的快速(很长)衬垫:
my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);
我需要类似的功能(但有所不同),以便根据用户名和当前时间生成唯一的ID。所以:
window.newId = ->
# create a number based on the username
unless window.userNumber?
window.userNumber = 0
for c,i in window.MyNamespace.userName
char = window.MyNamespace.userName.charCodeAt(i)
window.MyNamespace.userNumber+=char
((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()
产生:
2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc
编辑2015年6月:对于新代码,我使用shortid:https://www.npmjs.com/package/shortid
感谢mar10的示例,我找到了一种在FNV-1a的C#AND Javascript中获得相同结果的方法。如果存在unicode字符,则出于性能原因将其上部丢弃。不知道为什么在散列时维护它们会有所帮助,因为目前仅散列url路径。
C#版本
private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5; // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193; // 16777619
// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
// byte[] arr = Encoding.UTF8.GetBytes(s); // 8 bit expanded unicode array
char[] arr = s.ToCharArray(); // 16 bit unicode is native .net
UInt32 hash = FNV_OFFSET_32;
for (var i = 0; i < s.Length; i++)
{
// Strips unicode bits, only the lower 8 bits of the values are used
hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
hash = hash * FNV_PRIME_32;
}
return hash;
}
// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
return unchecked((int)s.HashFnv32u());
}
JavaScript版本
var utils = utils || {};
utils.FNV_OFFSET_32 = 0x811c9dc5;
utils.hashFnv32a = function (input) {
var hval = utils.FNV_OFFSET_32;
// Strips unicode bits, only the lower 8 bits of the values are used
for (var i = 0; i < input.length; i++) {
hval = hval ^ (input.charCodeAt(i) & 0xFF);
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
return hval >>> 0;
}
utils.toHex = function (val) {
return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}
这是一种精致且性能更好的变体:
String.prototype.hashCode = function() {
var hash = 0, i = 0, len = this.length;
while ( i < len ) {
hash = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
}
return hash;
};
这符合Java对标准的实现 object.hashCode()
这也是只返回正哈希码的代码:
String.prototype.hashcode = function() {
return (this.hashCode() + 2147483647) + 1;
};
这是Java的匹配项,它只返回正的哈希码:
public static long hashcode(Object obj) {
return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}
请享用!
String.prototype.hashCode = function() {
var hash = 0, i, chr;
if (this.length === 0) return hash;
for (i = 0; i < this.length; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
来源:http: //werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
如果对任何人reduce
都有用,我会将前两个答案组合成一个允许浏览器使用的较旧版本,如果可用,它将使用快速版本,如果没有,则使用esmiralha的解决方案。
/**
* @see http://stackoverflow.com/q/7616461/940217
* @return {number}
*/
String.prototype.hashCode = function(){
if (Array.prototype.reduce){
return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
}
var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
var character = this.charCodeAt(i);
hash = ((hash<<5)-hash)+character;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
用法就像:
var hash = new String("some string to be hashed").hashCode();
编辑
根据我的jsperf测试,接受的答案实际上更快:http ://jsperf.com/hashcodelordvlad
原版的
如果有人感兴趣,这是一个改进的(更快)版本,它将在缺少reduce
数组功能的旧版浏览器上失败。
hashCode = function(s){
return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
}
单线箭头功能版本:
hashCode = s => s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)
几乎一半的答案是Java的实现,
String.hashCode
既不是高质量的也不是超快的。没什么特别的,每个字符仅乘以31。它可以在一行中简单有效地实现,并且使用以下命令可以更快Math.imul
:
hashCode=s=>{for(var i=0,h;i<s.length;i++)h=Math.imul(31,h)+s.charCodeAt(i)|0;return h}
有了这些,就更好了— cyrb53,一个简单但高质量的53位哈希。与任何 32位哈希相比,它速度非常快,提供了很好的哈希分布,并且冲突率大大降低。
const cyrb53 = function(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);
};
与众所周知的MurmurHash / xxHash算法相似,它使用乘法和Xorshift的组合来生成哈希,但是不够彻底。结果,它比JavaScript中的任何一种都要快,并且实现起来也很简单。
它实现了雪崩(非严格),这基本上意味着输入的细微变化在输出中的大变化,从而使得结果散列看起来是随机的:
0xc2ba782c97901 = cyrb53("a")
0xeda5bc254d2bf = cyrb53("b")
0xe64cc3b748385 = cyrb53("revenge")
0xd85148d13f93a = cyrb53("revenue")
您还可以为相同输入的备用流提供种子:
0xee5e6598ccd5c = cyrb53("revenue", 1)
0x72e2831253862 = cyrb53("revenue", 2)
0x0de31708e6ab7 = cyrb53("revenue", 3)
从技术上讲,它是一个64位哈希(并行的是两个不相关的32位哈希),但是JavaScript限于53位整数。如果需要,可以通过更改十六进制字符串或数组的返回行来使用完整的64位输出。
请注意,在性能至关重要的情况下,构造十六进制字符串会大大减慢批处理的速度。
return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];
只是为了好玩,这是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}
这应该比其他答案更安全,但在函数中,没有任何预加载源
我基本上创建了sha1的简化版。
您获取字符串的字节并将它们按4到32位的“单词”分组,
然后将每8个单词扩展到40个单词(以对结果产生更大的影响)。
这将转到哈希函数(最后一个减少),在该函数中我们对当前状态和输入进行一些数学运算。我们总是得到4个字。
这几乎是一个使用map,reduce ...而不是循环的单命令/单行版本,但是它仍然相当快
我们还将输出转换为十六进制以获取字符串而不是单词数组。
用法很简单。样品
"a string".hash()
将返回"88a09e8f9cc6f8c71c4497fbb36f84cd"