JavaScriptの文字列からハッシュを生成する


586

文字列を何らかの形式のハッシュに変換する必要があります。これはJavaScriptで可能ですか?

私はサーバーサイド言語を利用していないので、そのようにはできません。


7
MD5は安全ではないので、MD5を探してはいけません。
henrikstroem 2013

166
@henrikstroemハッシュする対象によって異なります。セキュリティ以外の目的でハッシュを作成するためにmd5を使用することに問題はありません。
Brad Koch 14年

7
@BradKochあなたが何をしているかに依存します。セキュリティの目的でmd5を使用することに問題はありません。パスワードをハッシュするためのより良い方法は確かにありますが、md5はURLへの署名のようなことをするのにちょうど良いです。
Paul Ferrett、2015年

81
ここでコメントでMD5が批評されている間、ほとんどすべての回答がはるかに悪いハッシュアルゴリズムを推奨し、多くの賛成票を獲得するのは面白いと思います。
domen

38
MD5を使用してダウンロードが無事に行われたことを確認しても、魔法のようにすべての同僚にパスワードが電子メールで送信されるわけではありません。
James M. Lay、

回答:


789
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が、LOTはより高速です。とても速いのでいいですし、31は小さな素数です。そこで勝利。
corsiKa 2009

41
私はjsperf(jsperf.com/hashing-strings)でいくつかのテストを行いましたが、ビット単位の関数は実際には数値ベースの関数よりも低速です。
スケリット2012年

17
@PeterAronZentaiなぜ「使えない」のですか?数値ベースのコード(hash * 31) + charによって生成される出力は((hash<<5)-hash)+char、非常に長い文字列(100万を超える文字を含む文字列でテストしました)であっても、シフトベースのコードによって生成される出力と同じであるため、用語で「使用不可能」ではありません精度の。複雑さは、数値ベースバージョンとシフトベースバージョンの両方でO(n)であるため、複雑さの点で「使用不可能」ではありません。
TachyonVortex 2013

13
誰もが出力の一意性について(またはそうでないことについて)コメントできますか?具体的には、長さが未満の文字列に対してのみこのハッシュを使用する場合、衝突が発生する可能性のないn最大のものは何nですか?
Don McCurdy 2014年

34
これがStringプロトタイプに必要な(またはすべき)理由はありますか?例だけでは効果的/効率的ではないでしょうか。var hashCode = function hashCode (str) {etc...}?そして、次のように使用しhashCode("mystring")ますか?
ラットトレイ2014

146

編集

私の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

46
変。私はそれをテストしたところ、受け入れられた回答よりも遅いことがわかりました。jsperf.com/hashcodelordvlad
lordvlad

113
@lordvladさん、実際に自分の答えをテストし、遅くなったときに報告してくれました。
mikemaccana 14

9
私はちょうど実現:それは私のバージョンは、新しいメモリを割り当て、すべての文字をコピーし、最初の配列に文字列を有効にする必要があるため受け入れられた答えは、より高速であることを完璧に理にかなって...
lordvlad

5
[] .reduce.call(str、(p、c、i、a)=>(p << 5)-p + a.charCodeAt(i)、0);
めまい

108

注:最高の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
When短い 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文字になります。読みやすく出力に認識し、それは私の個人的な意見だする
mar10

ああ、わかりました。小型のためhval(hval >>> 0).toString(16)ゼロであなたので、パッドには、8文字未満であるかもしれません。(hval >>> 0).toString(16)常に正確に8文字の文字列が表示されるため、混乱しました。
Manuel Meurer 2014年

3
私がこの答えを気に入っているのは、非常に優れた分散ハッシュが生成されるためです。ここで提案されている他の関数は、結果としてハッシュ値を作成します。たとえば、 `hash(" example1 ")-ha​​sh(" example2 ")== 1"ですが、これははるかに予測不可能です
GavinoGrifoni

1
「FNV-1aはDJB2よりも良いディストリビューションを持っていますが、遅いです」-ES6 Math.imul関数を使用して実装した場合、FNV1aは非常に高速であると言えるでしょう。それだけでもトップベンチマークになり、長期的にはDJB2よりも最終的にはより良い選択になります。
bryc

64

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

4
しかし、これらのどれよりもはるかに遅い:https
//jsperf.com/hashing-strings

また、改行を削除して3行だけにすると、最速の "レトロ"ソリューションも実際には小さくなります。
AndyO 2017

2
これで肯定的でありながらユニークな結果のみを生み出す方法はありますか?
2017年

3
@deekshith受け入れられた答えはhash |= 0、32ビット整数に変換するために使用します。この実装にはありません。これはバグですか?
スキマスイッチ

48

答えのほぼ半分はJavaの実装でString.hashCodeあり、高品質でも超高速でもありません。これは特別なことではなく、文字ごとに31倍されます。1行で簡単かつ効率的に実装でき、次のようにするとはるかに高速になりMath.imulます。

hashCode=s=>{for(var i=0,h;i<s.length;i++)h=Math.imul(31,h)+s.charCodeAt(i)|0;return h}

これで問題は解決しました。単純なもので高品質の53ビットハッシュであるcyrb53です。これは非常に高速で、非常に優れたハッシュ分散を提供し 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ビットハッシュが2つ並列)ですが、JavaScriptは53ビット整数に制限されています。必要に応じて、完全な64ビット出力を引き続き使用できます 16進文字列または配列の戻り行を変更するます。

16進文字列を作成すると、パフォーマンスが重要な状況でバッチ処理が大幅に遅くなる可能性があることに注意してください。

return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];

楽しみのために、FNVやDJB2よりも高品質の89文字の最小32ビットハッシュを以下に示します。

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 '10年

IE 11の失敗:オブジェクトはプロパティまたはメソッドをサポートしていません'imul'
BachT

2
@BachT ポリフィルまたは完全なES6シムを使用できます。しかし、IE11は2009年に悲劇的に凍結され、更新はありません。
bryc

28

それが誰かを助ける場合、私は上位2つの回答を古いブラウザートレラントバージョンに組み合わせました。これは、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 Sayyed 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 2016

8
@koolaangそれは左くそ演算子、developer.mozilla.org
mmm

29
@momomo左シフトですか?
wdh 2017年

2
@momomo彼はそれがなぜゼロビットの左シフトだったのかと尋ねていたと思います。
jpfx1342 2017

3
@メイコン(2 ^ 32-1)
Nijraj Gelani 2018

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
同意する。16進数への変換は少し異なります...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

3
文字列の暗号化ハッシュ関数は少々やり過ぎです。crypto正確には機能しません。
bryc 2018年

テストを実行している人に依存する必要のない信頼できる品質のランダム、組み込み(カスタム実装は不要)、シード可能、そしてゲームマップを生成するために数百の数値しか必要としない、これは完璧に思えました。しかし、それを同期的に行う方法は絶対にないことがわかりました。シードされたランダムエンジンを呼び出すたびに非同期のコールバックを提供する必要があるため、コードが非常に読みにくくなり、ばかげて見えます。:私は最後に、私はこの回答からxmur3 + SFC32で行かなければならなかったので、私は、この安っぽいcrypto.subtleインタフェースを思い付いた誰得ることはありませんstackoverflow.com/a/47593316/1201863
リュック

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さて、私はshortidと呼ばれるモジュールを使用します:npmjs.com/package/shortid
jcollum

1
shortidでユーザー名をどのように使用していますか?それだけでIDを生成するようだが、私は、あなたが文字列からハッシュを生成するために使用しているか表示されない
cyberwombat

1
この回答には3つの反対票があります。私の人生にとって、その理由は想像もできません。誰も何も言わなかった...:-/
jcollum

1
@jcollumだから、私は古い質問にほとんど答えません。答えを修正した後でも、バランスを取るために誰も来ません。
bryc

5

FNVのMultiply+Xor方法に基づく私の迅速な(非常に長い)1つのライナー:

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

5

SubtleCrypto.digest

私はサーバーサイド言語を利用していないので、そのようにはできません。

あなたはその方法でそれ行うことができないと確信していますか?

進化を続ける言語であるJavascriptを使用していることを忘れていませんか?

お試しください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.")));
})();


これはあなたの2年前の海道の回答とどう違うのですか?
Luc

@Lucそうではありません。
КонстантинВан

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

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 2018

2

これは他のいくつかの回答よりも少し安全なハッシュになるはずですが、関数では、プリロードされたソースはありません

私はbasicly縮小さ作成された単純化 SHA1のバージョンを。
文字列のバイトを取り、4〜32ビットの「ワード」でグループ化します。
次に、8ワードごとに40ワードに拡張します(結果に大きな影響を与えるため)。
これは、現在の状態と入力を使用していくつかの計算を行うハッシュ関数(最後の削減)に移動します。私たちはいつも4つの言葉を出します。
これは、ループの代わりにmap、reduce ...を使用したほぼ1つのコマンド/ 1行のバージョンですが、それでもかなり高速です。

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

また、出力を16進数に変換して、単語配列ではなく文字列を取得します。
使い方は簡単です。例のため"a string".hash()に戻ります"88a09e8f9cc6f8c71c4497fbb36f84cd"


1

16進数の文字列に変換された文字コードを単純に連結した。これは比較的狭い目的に役立ちます。つまり、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"

大きな文字列を同様の方法でハッシュしたい場合は、個々の文字を連結するのではなく、charコードを減らして結果の合計を16進化できると思います。

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'

そのlibのソースコードは読み取りもできません。たった50kの縮小コードです。
bryc

1
@brycこれは、ベンダーコードが次のようになるはずです:)およびソースについては、github.com / puleos / object
Oleg Abrazhaev

縮小されたコードは35.4 KBで、ソース全体は14.2 KBですか?それは意味がありません。
bryc

2
@brycこの行を検討しましたか?var crypto = require('crypto');。ビルド中に、ベンダーからのこの依存関係コードを縮小バージョンに追加すると思います。
Oleg Abrazhaev

本当にオブジェクトをハッシュする必要がある場合は、any-serialize記述して、任意のオブジェクトをソートキーでシリアル化し、cyrb53で base36ハッシュを生成しました。
Polv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.