从Java脚本中的字符串生成哈希


585

我需要将字符串转换为某种形式的哈希。这在JavaScript中可行吗?

我没有使用服务器端语言,所以我不能那样做。


7
MD5不安全,所以不要寻找那个。
henrikstroem

166
@henrikstroem取决于您的哈希值;使用md5出于非安全目的创建哈希没有任何问题。
布拉德·科赫

7
@BradKoch取决于您在做什么;使用md5出于安全目的没有错。当然,可以使用更好的方法来散列密码,但是md5可以很好地完成对URL进行签名等操作。
Paul Ferrett'3

81
我觉得很有趣,尽管在这里的评论中批评了MD5,但几乎所有答案都建议使用更差的哈希算法并获得很多支持。
domen,2016年

38
使用MD5验证下载是否完整无缺,这绝对不会将您的密码通过电子邮件发送给您的所有同事。
James M. Lay

Answers:


788
Object.defineProperty(String.prototype, 'hashCode', {
  value: function() {
    var hash = 0, i, chr;
    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/


22
这与Java中使用的相同。该hash << 5 - hash是一样的hash * 31 + char,但速度快了很多。很好,因为它是如此之快,而且31是一个很小的素数。在那双赢。
corsiKa 2011年

41
我对jsperf(jsperf.com/hashing-strings)进行了一些测试,按位函数实际上比基于数字的函数慢。
skerit 2012年

17
@PeterAronZentai为什么它“不可用”?基于数字的代码(hash * 31) + char产生的输出与基于移位的代码产生的输出相同((hash<<5)-hash)+char,即使对于非常长的字符串(我已经用包含超过一百万个字符的字符串对其进行了测试),因此在术语上也不是“不可用的”准确性。对于基于数字的版本和基于移位的版本,复杂度均为O(n),因此就复杂度而言,它并非“无法使用”。
TachyonVortex

13
任何人都可以评论输出的唯一性吗?具体来说,如果我仅对长度小于的字符串使用此哈希,那么我n最大n可能不会发生冲突的最大字符串是什么?
Don McCurdy 2014年

34
是否有任何理由(或应该)在String原型上?仅仅拥有例如,是否会降低效率/效率?var hashCode = function hashCode (str) {etc...}?然后用作hashCode("mystring")
拉特里

145

编辑

根据我的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)

3
有没有一种方法可以使哈希仅是正数?
Prosto Trader 2013年

45
奇怪的。我刚刚测试了它,结果比接受的答案慢了很多。jsperf.com/hashcodelordvlad
lordvlad 2013年

112
好人@lordvlad,实际上是测试自己的答案,然后在速度变慢时报告。
mikemaccana 2014年

9
我刚刚意识到:完全可以接受的答案是更快的,因为我的版本必须先将字符串转换成数组,分配新的内存并复制每个字符...
lordvlad 2015年

5
[] .reduce.call(str,(p,c,i,a)=>(p << 5)-p + a.charCodeAt(i),0);
头昏

107

注意:即使使用最佳的32位哈希,冲突迟早也会发生。

哈希冲突概率可以计算为 1-e ^(-k(k-1)/ 2N,近似为 k ^ 2 / 2N请参见此处)。这可能比直觉所暗示的要高:
假设一个32位哈希且k = 10,000个项目,则发生碰撞的概率为1.2%。对于77,163个样本,概率变为50%!(计算器)。
我建议在底部的一种解决方法。

在回答这个问题时, 哪种哈希算法最适合唯一性和速度?,伊恩·博伊德(Ian Boyd)进行了深入的分析。简而言之(据我的解释),他得出的结论是Murmur最好,其次是FNV-1a。
esmiralha提出的Java String.hashCode()算法似乎是DJB2的一种变体。

  • FNV-1a比DJB2具有更好的分布,但速度较慢
  • DJB2比FNV-1a快,但往往会产生更多碰撞
  • MurmurHash3比DJB2和FNV-1a更好和更快(但是优化的实现比FNV和DJB2需要更多的代码行)

在这里大的输入字符串的一些基准:http://jsperf.com/32-bit-hash
输入字符串被散列,杂音的性能下降,相对于DJ2B和FNV-1A:http://jsperf.com/32-散列/ 3

因此,一般而言,我会推荐murmur3。
参见此处以获取JavaScript实现:https//github.com/garycourt/murmurhash-js

如果输入字符串短并且性能比分发质量更重要,请使用DJB2(由esmiralha接受的答案提出)。

如果质量和小的代码大小比速度更重要,那么我将使用FNV-1a的此实现(基于此代码)。

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as 
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

提高碰撞概率

如此处所述,我们可以使用以下技巧扩展哈希位大小:

function hash64(str) {
    var h1 = hash32(str);  // returns 32 bit (as 8 byte hex string)
    return h1 + hash32(h1 + str);  // 64 bit (as 16 byte hex string)
}

请谨慎使用,但不要期望过高。


你为什么("0000000" + (hval >>> 0).toString(16)).substr(-8);呢?那不一样(hval >>> 0).toString(16)吗?
Manuel Meurer 2014年

3
这会加上前导'0',因此生成的哈希值始终为8个字符。在输出中更易于阅读和识别,但这是我的个人观点
2014年

嗯,知道了。对于small hval(hval >>> 0).toString(16)可能少于8个字符,因此请使用零填充。我很困惑,因为(hval >>> 0).toString(16)总是给我一个正好8个字符的字符串。
Manuel Meurer 2014年

3
我喜欢这个答案,因为它产生了更好的分布式哈希:这里提出的其他函数将产生随后的哈希值。例如`散列( “例1”) -散列( “例2”)== 1" ,而这个人是更不可预测的。
GavinoGrifoni

1
回应“ FNV-1a的分布比DJB2更好,但速度较慢”-我认为应该说,使用ES6 Math.imul功能实现FNV1a可以非常快。从长远来看,仅此一项就使其成为顶级基准,并且最终比DJB2更好。
bryc

65

基于ES6中公认的答案。体积更小,可维护并且可以在现代浏览器中运行。

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));

编辑(2019-11-04)

单线箭头功能版本:

const hashCode = s => s.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0)

// test
console.log(hashCode('Hello!'))


1
感谢分享,我str += ""在散列之前添加了代码,以避免str.split is not a function在将非字符串作为参数传递时引发异常
BeetleJuice 2016年

4
但是比任何一个都慢得多:https
//jsperf.com/hashing-strings

我还注意到,如果删除换行符,则最快的“复古”解决方案实际上也较小,因此它只有3行。
AndyO

2
有什么办法可以产生积极但仍然独特的结果?
Dids '11

3
@deekshith可接受的答案用于hash |= 0转换为32位int。此实现没有。这是错误吗?
Sukima

48

几乎一半的答案是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];

只是为了好玩,这是一个最小的32位哈希,包含89个字符,其质量甚至比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}

4
哇,这比通常的* 31输入短(或类似)输入要好得多。:)
lapo

2
在哪里ch初始化?
hellowill89

3
@ hellowill89糟糕,我忘了声明它,并且正在渗入全球范围。现在修复,谢谢:')
bryc

IE 11失败:对象不支持property或method 'imul'
BachT

2
@BachT您可以使用填充工具或完整ES6垫片。但是IE11在2009年被冻结,没有任何更新。
bryc

28

如果对任何人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 = "some string to be hashed".hashCode();

如何优化此代码以在每个浏览器中更快地运行。String.prototype.hashCode = function(){ var hash = 5381; if (this.length === 0) return hash; for (var i = 0; i < this.length; i++) { var character = this.charCodeAt(i); hash = ((hash<<5)+hash)^character; // Convert to 32bit integer } return hash; }
Musakkhir说2015年

26

这是一种精致且性能更好的变体:

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;
}

请享用!


2
好的答案,但是<< 0的目的是什么?
koolaang '16

8
@koolaang是左便便的操作者,developer.mozilla.org
mmm

29
@momomo你的意思是左边
wdh

2
@momomo我想他在问为什么这是零位的左移。
jpfx1342

3
@Maykonn(2 ^
32-1

24

令我惊讶的是,还没有人谈论新的SubtleCrypto API

要从字符串获取哈希,可以使用subtle.digest方法:

function getHash(str, algo = "SHA-256") {
  let strBuf = new TextEncoder('utf-8').encode(str);
  return crypto.subtle.digest(algo, strBuf)
    .then(hash => {
      window.hash = hash;
      // here hash is an arrayBuffer, 
      // so we'll connvert it to its hex version
      let result = '';
      const view = new DataView(hash);
      for (let i = 0; i < hash.byteLength; i += 4) {
        result += ('00000000' + view.getUint32(i).toString(16)).slice(-8);
      }
      return result;
    });
}

getHash('hello world')
  .then(hash => {
    console.log(hash);
  });


4
我同意。转换为十六进制的操作可能有所不同...var promise = crypto.subtle.digest({name: "SHA-256"}, Uint8Array.from(data)); promise.then(function(result){ console.log(Array.prototype.map.call(new Uint8Array(result), x => x.toString(16).padStart(2, '0')).join('')); });
Denis Giffeler '17

3
字符串的加密哈希函数有点过分.. crypto并不是完全有效。
bryc

可靠的质量随机性,而不必依赖运行测试的人员,内置的(无需自定义实现),可播种的,而且我只需要数百个数字即可生成游戏地图,这似乎很完美。但事实证明,绝对没有办法同步进行。每次调用种子随机引擎时,都必须提供一些异步回调,这使得代码非常难以阅读,而且看起来很荒谬。我不知道是谁提出了这个糟糕的crypto.subtle接口,所以最终我不得不从这个答案中选择xmur3 + sfc32:stackoverflow.com/a/47593316/1201863
Luc

7

感谢mar10的示例,我找到了一种在FNV-1a的C#和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);
}

@mathiasrw Unicode字符可能在内存中超过8位,因此我假设0xFF只是掩盖了该范围之外的任何内容。在此处查看有关charCodeAt()的更多信息:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
djabraham

如果有ES6(所有现代引擎都支持),则Math.imul可以将其用于乘法步骤,从而大大提高性能。唯一的问题是,没有shim它将无法在IE11中工作。
bryc

6

一种快速简洁的方法,从这里改编而成:

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}

5

我需要一个类似的函数(但有所不同)来根据用户名和当前时间生成一个唯一的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


2
@ t0r0X现在好了,我用一个模块调用短ID:npmjs.com/package/shortid
jcollum

1
您如何使用带有shortid的用户名?这似乎只是生成的ID,但我不知道你是如何使用来产生一个字符串的哈希
cyberwombat

1
该答案有3下注。对于我的一生,我无法想象为什么。没有人说什么...:-/
jcollum

1
@jcollum这就是为什么我几乎从不回答过时的问题的原因。即使您确定了答案,也没有人来平衡它。
bryc

5

我基于FNV Multiply+Xor方法的快速(很长)衬垫:

my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);

5

微妙的加密摘要

我没有使用服务器端语言,所以我不能那样做。

你肯定你不能这样做

您是否忘了您正在使用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.")));
})();


这与您前两年的Kaiido的答案有何不同?
吕克(Luc)

@Luc显然不是。
43КонстантинВан

3

我参加聚会有点晚,但是您可以使用以下模块:crypto

const crypto = require('crypto');

const SALT = '$ome$alt';

function generateHash(pass) {
  return crypto.createHmac('sha256', SALT)
    .update(pass)
    .digest('hex');
}

此函数的结果始终是64字符串;像这样的东西:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"


2

我结合了两种解决方案(用户esmiralha和lordvlad)来获得一个函数,该函数对于支持js函数reduce()并仍与旧浏览器兼容的浏览器应该更快:

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);   
    } else {

        var hash = 0, i, chr, len;
        if (this.length == 0) return hash;
        for (i = 0, len = this.length; i < len; i++) {
        chr   = this.charCodeAt(i);
        hash  = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
        }
        return hash;
    }
};

例:

my_string = 'xyz';
my_string.hashCode();

2

如果要避免冲突,则可能需要使用安全散列,例如SHA-256。有几种JavaScript SHA-256实现。

我编写了测试以比较几种哈希实现,请参阅https://github.com/brillout/test-javascript-hash-implementations

或访问http://brillout.github.io/test-javascript-hash-implementations/来运行测试。


1
使用安全的密码哈希可能非常慢。避免冲突是位宽而不是安全性的产物。对于大多数用途而言,128位非加密哈希甚至64位应该绰绰有余。MurmurHash3_x86_128相当快,发生碰撞的几率很小。
bryc

2

这应该比其他答案更安全一些,但是在函数中,没有任何预加载的源

我基本上创建了sha1的简化版
您获取字符串的字节并将它们按4到32位的“单词”分组,
然后将每8个单词扩展到40个单词(以对结果产生更大的影响)。
这到散列函数(最后一个减少),我们在此使用当前状态和输入进行一些数学运算。我们总是得到4个字。
这几乎是使用map,reduce ...而不是循环的单命令/单行版本,但是它仍然相当快

String.prototype.hash = function(){
    var rot = (word, shift) => word << shift | word >>> (32 - shift);
    return unescape(encodeURIComponent(this.valueOf())).split("").map(char =>
            char.charCodeAt(0)
        ).reduce((done, byte, idx, arr) =>
            idx % 4 == 0 ? [...done, arr.slice(idx, idx + 4)] : done
        , []).reduce((done, group) =>
            [...done, group[0] << 24 | group[1] << 16 | group[2] << 8 | group[3]]
        , []).reduce((done, word, idx, arr) =>
            idx % 8 == 0 ? [...done, arr.slice(idx, idx + 8)] : done
        , []).map(group => {
            while(group.length < 40)
                group.push(rot(group[group.length - 2] ^ group[group.length - 5] ^ group[group.length - 8], 3));
            return group;
        }).flat().reduce((state, word, idx, arr) => {
            var temp = ((state[0] + rot(state[1], 5) + word + idx + state[3]) & 0xffffffff) ^ state[idx % 2 == 0 ? 4 : 5](state[0], state[1], state[2]);
            state[0] = rot(state[1] ^ state[2], 11);
            state[1] = ~state[2] ^ rot(~state[3], 19);
            state[2] = rot(~state[3], 11);
            state[3] = temp;
            return state;
        }, [0xbd173622, 0x96d8975c, 0x3a6d1a23, 0xe5843775,
            (w1, w2, w3) => (w1 & rot(w2, 5)) | (~rot(w1, 11) & w3),
            (w1, w2, w3) => w1 ^ rot(w2, 5) ^ rot(w3, 11)]
        ).slice(0, 4).map(p =>
            p >>> 0
        ).map(word =>
            ("0000000" + word.toString(16)).slice(-8)
        ).join("");
};

我们还将输出转换为十六进制以获取字符串而不是单词数组。
用法很简单。样品"a string".hash()将返回"88a09e8f9cc6f8c71c4497fbb36f84cd"


1

我去了一个简单的串联的字符代码,转换为十六进制字符串。这有一个相对狭窄的目的,即只需要与服务器端交换SHORT字符串(例如标题,标签)的哈希表示,由于不相关的原因,就不能轻易实现已接受的hashCode Java端口。显然这里没有安全应用程序。

String.prototype.hash = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.map.call(range, function(i) {
    return self.charCodeAt(i).toString(16);
  }).join('');
}

使用Underscore可以使它更简洁,更易于浏览。例:

"Lorem Ipsum".hash()
"4c6f72656d20497073756d"

我想如果您想以类似的方式对较大的字符串进行哈希处理,则可以减少字符代码并十六进制化所得的和,而不是将各个字符连接在一起:

String.prototype.hashLarge = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.reduce.call(range, function(sum, i) {
    return sum + self.charCodeAt(i);
  }, 0).toString(16);
}

'One time, I hired a monkey to take notes for me in class. I would just sit back with my mind completely blank while the monkey scribbled on little pieces of paper. At the end of the week, the teacher said, "Class, I want you to write a paper using your notes." So I wrote a paper that said, "Hello! My name is Bingo! I like to climb on things! Can I have a banana? Eek, eek!" I got an F. When I told my mom about it, she said, "I told you, never trust a monkey!"'.hashLarge()
"9ce7"

这种方法自然会带来更多的冲突风险,尽管您可以在reduce方法中摆弄一些算术,但是您希望分散并延长哈希值。


1

@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;
}

1

添加此代码是因为还没有人这样做,并且似乎需要使用散列来实现它,但是它总是做得很差。

这需要一个字符串输入,以及您希望哈希值等于的最大数字,并根据字符串输入生成一个唯一的数字。

您可以使用它来生成图像数组的唯一索引(如果要为用户返回特定的化身,该化身是随机选择的,但也是根据其名称选择的,因此它将始终分配给具有该名称的人)。

当然,您也可以使用此方法将索引返回到颜色数组中,例如根据某人的名字生成唯一的头像背景颜色。

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);
}

-1

我看不出有任何理由使用此过于复杂的密码而不是使用现成的解决方案(如对象哈希库等)。依靠供应商的生产率更高,可以节省时间并降低维护成本。

只需使用https://github.com/puleos/object-hash

var hash = require('object-hash');

hash({foo: 'bar'}) // => '67b69634f9880a282c14a0f0cb7ba20cf5d677e9'
hash([1, 2, 2.718, 3.14159]) // => '136b9b88375971dff9f1af09d7356e3e04281951'

该库的源代码甚至无法读取。.仅50k的缩小代码。
bryc

1
@bryc就是供应商代码的样子:),对于源代码,您可以检查github.com/puleos/object-hash/blob/master/index.js
Oleg Abrazhaev,

压缩代码为35.4 KB,而完整代码为14.2 KB?这是没有意义的。
bryc

2
@bryc您考虑过这一行吗?var crypto = require('crypto');。我认为它将在构建过程中以最小版本添加来自供应商的此依赖项代码。
Oleg Abrazhaev '19

如果您真的需要对对象进行哈希处理,我编写了any-serialize来使用排序键序列化ANY Object,然后使用cyrb53生成base36哈希。
Polv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.