javascript - जावास्क्रिप्ट / jQuery में स्ट्रिंग से हैश उत्पन्न करें


मुझे स्ट्रिंग को किसी प्रकार के हैश में कनवर्ट करना होगा। जावास्क्रिप्ट / jQuery में यह संभव है?

मैं एक सर्वर-साइड भाषा का उपयोग नहीं कर रहा हूं, इसलिए मैं इसे इस तरह से नहीं कर सकता।



Answers






संपादित करें

मेरे 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);              
}



नोट: यहां तक ​​कि सबसे अच्छी 32-बिट हैश के साथ, आपको इस तथ्य से निपटना होगा कि टकराव जल्दी या बाद में हो जाएगा । Ie दो अलग-अलग इनपुट स्ट्रिंग कम से कम 1: 2 ^ 32 की संभावना के साथ एक ही हैश मान वापस करेगा।

इस सवाल का उत्तर में जो हैशिंग एल्गोरिदम अद्वितीयता और गति के लिए सबसे अच्छा है? , इयान बॉयड ने गहन विश्लेषण में एक अच्छा पोस्ट किया। संक्षेप में (जैसा मैं व्याख्या करता हूं), वह निष्कर्ष पर आता है कि मुंजार सबसे अच्छा है, इसके बाद एफ एन वी -1 ए
जावा की स्ट्रिंगहैशकोड () एल्गोरिथ्म जो कि एस्मिराल्हा प्रस्तावित डीजेबी 2 का एक प्रकार है।

  • एफएनवी-1 ए डीजेबी 2 की तुलना में बेहतर वितरण है, लेकिन धीमा है
  • डीजेबी 2 एफएनवी-1 ए की तुलना में तेज है, लेकिन अधिक टक्कर पैदा करने की प्रवृत्ति है
  • मुरमुरहेश 3 डीजेबी 2 और एफएनवी-1 ए से बेहतर और तेज है (लेकिन अनुकूलित ओम लगाने योग्यता एफएनवी और डीजेबी 2 से अधिक कोड की आवश्यकता है)

यहाँ बड़े इनपुट स्ट्रिंग वाले कुछ बेंचमार्क: http://jsperf.com/32-bit-hash
डीजे 2 बी और एफएनवी-1 ए के सापेक्ष, कम इनपुट तारों को धोया जाता है, बड़बड़ाहट का प्रदर्शन बूँदें: http://jsperf.com/32-bit-hash/3

तो सामान्य तौर पर मैं बड़बड़ाहट 3 की सिफारिश करूँगा।
जावास्क्रिप्ट कार्यान्वयन के लिए यहां देखें: https://github.com/garycourt/murmurhash-js

अगर इनपुट स्ट्रिंग्स कम हैं और डिस्ट्रिब्यूशन की गुणवत्ता के मुकाबले प्रदर्शन अधिक महत्वपूर्ण है, तो डीजेबी 2 का प्रयोग करें (जैसा कि एस्मिराल्हा द्वारा स्वीकार किए गए उत्तर के अनुसार प्रस्तावित है)।

अगर गुणवत्ता और छोटे कोड का आकार गति से अधिक महत्वपूर्ण है, तो मैं इसे 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;
}



यदि यह किसी को मदद करता है, तो मैंने शीर्ष दो जवाबों को एक पुराने-ब्राउज़र-सहिष्णु संस्करण में जोड़ दिया, जो reduce संस्करण उपलब्ध है, यदि reduce उपलब्ध है और एस्मीरलाहा के समाधान पर वापस आ जाए तो ऐसा नहीं है।

/**
 * @see http://.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();



ES6 में स्वीकार किए गए उत्तर के आधार पर आधुनिक, ब्राउज़र में छोटा, रख-रखाव और काम करता है

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

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




यह एक परिष्कृत और बेहतर प्रदर्शन वाला संस्करण है:

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

यह मानक object.hashCode() जावा के कार्यान्वयन से मेल खाता है object.hashCode()

यहां भी एक है जो केवल सकारात्मक हैशोडोड देता है:

String.prototype.hashcode = function() {
    return (this.hashCode() + 2147483647) + 1;
};

और यहां जावा के लिए एक मेल खाता है जो केवल सकारात्मक हैशोडोड देता है:

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}

का आनंद लें!




Mar10 द्वारा उदाहरण के लिए धन्यवाद, मुझे एक ही परिणाम सी # और एफएएनवी -1 ए के लिए जावास्क्रिप्ट में प्राप्त करने का एक तरीका मिला। यदि यूनिकोड वर्ण मौजूद हैं, तो ऊपरी भाग को प्रदर्शन के लिए त्याग दिया जाता है। पता नहीं क्यों कि उन लोगों को बनाए रखने में सहायक क्यों होगा, जब हिसिंग, जैसा कि अब केवल हैशिंग यूआरएल पथ है

सी # संस्करण

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

जावास्क्रिप्ट संस्करण

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



उपयोगकर्ता नाम और वर्तमान समय के आधार पर एक अद्वितीय-आईश आईडी बनाने के लिए मुझे एक समान फ़ंक्शन की आवश्यकता है (लेकिन अलग है)। इसलिए:

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 को संपादित करें: नए कोड के लिए मैं शॉर्टिड का उपयोग करता हूं: https://www.npmjs.com/package/shortid




मुझे आश्चर्य है कि कोई भी नई सूक्ष्मक्रिप 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);
  });




एक तेज और संक्षिप्त जो यहां से अनुकूलित किया गया था:

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



मैंने एक ऐसा समारोह प्राप्त करने के लिए दो समाधान (प्रयोक्ता एस्मराल्ह और स्वामीजीद) को जोड़ दिया है जो ब्राउज़रों के लिए तेज़ होना चाहिए जो जेएस समारोह को कम करते हैं () और पुराने ब्राउज़रों के साथ अभी भी संगत:

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



मैं हेक्स स्ट्रिंग में कनवर्ट किए गए चार कोडों के एक सरल संयोजन के लिए गया था। यह एक अपेक्षाकृत संकीर्ण प्रयोजन प्रदान करता है, अर्थात् बस एक छोटी सी स्ट्रिंग (जैसे शीर्षक, टैग) के एक हैश प्रतिनिधित्व की जरूरत है, जो किसी सर्वर साइड के साथ आदान-प्रदान किया जाता है, प्रासंगिक कारणों से स्वीकार किए गए हैशकोड जावा पोर्ट को आसानी से लागू नहीं किया जा सकता है जाहिर है यहां कोई सुरक्षा आवेदन नहीं है।

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

इसे अंडरस्कोर के साथ अधिक संक्षिप्त और ब्राउज़र-सहिष्णु बनाया जा सकता है। उदाहरण:

"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"

इस पद्धति से टकराव का स्वाभाविक रूप से अधिक जोखिम है, हालांकि आप इसे कम करने में अंकगणित के साथ बेला सकते हैं, हालांकि आप चाहते हैं कि विविधता और हंस को बढ़ाएं।




यदि आप टकराव से बचने के लिए चाहते हैं तो आप SHA-256 जैसे सुरक्षित हैश का उपयोग करना चाह सकते हैं। कई जावास्क्रिप्ट एसएचए -256 कार्यान्वयन हैं।

मैंने कई हॅश कार्यान्वयन की तुलना करने के लिए परीक्षण लिखा था, https://github.com/brillout/test-javascript-hash-implementations देखें

या परीक्षण चलाने के लिए http://brillout.github.io/test-javascript-hash-implementations/ पर जाएं।




@ एस्मिराला के जवाब का थोड़ा सा सरलीकृत संस्करण।

मैं इस संस्करण में स्ट्रिंग को ओवरराइड नहीं करता, क्योंकि इसके परिणामस्वरूप कुछ अवांछित व्यवहार हो सकते हैं।

function hashCode(str) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
        hash = ~~(((hash << 5) - hash) + str.charCodeAt(i));
    }
    return hash;
}



उदाहरण के लिए, इस समाधान के साथ हम कुछ समस्या से बचने के लिए वर्ण सेट को निर्दिष्ट कर सकते हैं, उदाहरण के लिए, मानों को संग्रहीत या अनुप्रयोगों के बीच भेजा जाता है: जब परिणाम स्ट्रिंग (हैश) प्रतिशत एन्कोडिंग उत्पन्न करता है और वह स्ट्रिंग नियंत्रक को दृश्य से GET विधि का उपयोग करने के लिए भेजा जाता है परत।

function doHashCode() {
    String.prototype.hashCode = function () {
        var text = "";
        var possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        for (var i = 0; i < 15; i++)
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        return text;
    }

    var hash = new String().hashCode();
    $('#input-text-hash').val(hash); // your html input text

}