ฉันต้องการแปลงสตริงเป็นแฮชบางรูปแบบ เป็นไปได้ใน JavaScript?
ฉันไม่ได้ใช้ภาษาฝั่งเซิร์ฟเวอร์ดังนั้นฉันจึงไม่สามารถทำเช่นนั้นได้
ฉันต้องการแปลงสตริงเป็นแฮชบางรูปแบบ เป็นไปได้ใน JavaScript?
ฉันไม่ได้ใช้ภาษาฝั่งเซิร์ฟเวอร์ดังนั้นฉันจึงไม่สามารถทำเช่นนั้นได้
คำตอบ:
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/
hash << 5 - hash
เป็นเช่นเดียวhash * 31 + char
แต่เร็วมาก มันดีเพราะมันเร็วมากและ 31 ก็เป็นไพรม์เล็ก ๆ ชนะที่นั่น
(hash * 31) + char
จะเหมือนกับผลลัพธ์ที่ผลิตโดยรหัส shift-based ((hash<<5)-hash)+char
แม้สำหรับสายยาวมาก (ฉันได้ทดสอบกับสตริงที่มีมากกว่าล้านตัวอักษร) ดังนั้นจึงไม่ใช่ "ใช้ไม่ได้" ในแง่ ของความถูกต้อง ความซับซ้อนคือ O (n) สำหรับทั้งเวอร์ชันที่อิงตัวเลขและ shift-based ดังนั้นจึงไม่ใช่ "ใช้ไม่ได้" ในแง่ของความซับซ้อน
n
สิ่งที่ใหญ่ที่สุดn
ที่ฉันไม่สามารถชนได้คืออะไร
var hashCode = function hashCode (str) {etc...}
? แล้วใช้เป็นhashCode("mystring")
?
แก้ไข
จากการทดสอบ jsperf ของฉันคำตอบที่ยอมรับนั้นเร็วขึ้นจริง: http://jsperf.com/hashcodelordvlad
ORIGINAL
หากใครสนใจนี่คือรุ่นปรับปรุง (เร็วกว่า) ซึ่งจะล้มเหลวในเบราว์เซอร์รุ่นเก่าที่ไม่มี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)
หมายเหตุ:แม้จะมีแฮชขนาด 32 บิตที่ดีที่สุดการชนก็จะเกิดขึ้นไม่ช้าก็เร็ว
ความน่าจะเป็นของการชนกันของแฮชสามารถคำนวณได้ว่าเป็น ประมาณ ( ดูที่นี่ ) สิ่งนี้อาจสูงกว่าสัญชาตญาณแนะนำ:
สมมติว่ามีแฮชแบบ 32 บิตและ k = 10,000 รายการการชนจะเกิดขึ้นโดยมีความน่าจะเป็น 1.2% สำหรับตัวอย่าง 77,163 ความน่าจะเป็น 50%! ( เครื่องคิดเลข )
ฉันแนะนำวิธีแก้ปัญหาที่ด้านล่าง
ในคำตอบสำหรับคำถามนี้
อัลกอริทึมการแฮชแบบใดดีที่สุดสำหรับความเป็นเอกลักษณ์และความเร็ว Ian Boyd โพสต์การวิเคราะห์เชิงลึกที่ดี ในระยะสั้น (ในขณะที่ฉันตีความมัน) เขาสรุปว่า Murmur นั้นดีที่สุดตามด้วย FNV-1a
String.hashCode () อัลกอริทึมของ Java ที่ esmiralha เสนอนั้นน่าจะเป็นตัวแปรของ 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)
ใช่ไหม
hval
, (hval >>> 0).toString(16)
อาจจะน้อยกว่า 8 ตัวอักษรเพื่อให้คุณแผ่นกับศูนย์ ฉันสับสนเพราะ(hval >>> 0).toString(16)
ส่งผลให้เกิดสตริงอักขระ 8 ตัวสำหรับฉันเสมอ
Math.imul
ฟังก์ชันES6 เพียงอย่างเดียวที่ทำให้มันเป็นมาตรฐานชั้นนำและในที่สุดก็เป็นทางเลือกที่ดีกว่า DJB2 ในระยะยาว
อ้างอิงจากคำตอบที่ยอมรับใน 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!'))
str += ""
ก่อนที่ hashing เพื่อหลีกเลี่ยงข้อstr.split is not a function
ผิดพลาดเกิดขึ้นเมื่อไม่มีการส่งสตริงเป็นพารามิเตอร์
hash |= 0
ในการแปลงเป็น 32 บิต การใช้งานนี้ไม่ได้ นี่เป็นข้อบกพร่องหรือไม่?
เกือบครึ่งคำตอบคือการใช้งานของ 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 บิตที่ไม่ได้เชื่อมโยงกันสองตัวในแนวขนาน) แต่จาวาสคริปต์นั้นถูก จำกัด ไว้ที่จำนวนเต็ม 53 บิต หากจำเป็นต้องใช้เอาต์พุต 64- บิตเต็มรูปแบบที่ยังคงสามารถใช้งานได้โดยการเปลี่ยนบรรทัดส่งคืนสำหรับสตริง hex หรืออาร์เรย์
โปรดทราบว่าการสร้างสตริง hex สามารถชะลอการประมวลผลแบทช์อย่างมากในสถานการณ์ที่มีความสำคัญต่อประสิทธิภาพ
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}
ch
เริ่มต้นที่ไหน
'imul'
วัตถุไม่สนับสนุนคุณสมบัติหรือวิธีการ
ถ้ามันช่วยทุกคนฉันรวมคำตอบสองข้อแรกเข้ากับเวอร์ชันที่ทนต่อเบราว์เซอร์ที่เก่ากว่าซึ่งใช้เวอร์ชันที่รวดเร็วถ้า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; }
นี่คือตัวแปรที่ได้รับการปรับปรุงและมีประสิทธิภาพดีกว่า:
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;
}
สนุก!
ฉันประหลาดใจเล็กน้อยที่ไม่มีใครพูดถึง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);
});
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('')); });
crypto
เป็นไปได้เล็กน้อย ..
ขอบคุณตัวอย่างจาก mar10 ฉันพบวิธีที่จะได้ผลลัพธ์เดียวกันใน C # AND Javascript สำหรับ FNV-1a หากมีตัวอักษร unicode อยู่ส่วนบนจะถูกยกเลิกเพื่อประสิทธิภาพ ไม่ทราบว่าทำไมจึงเป็นประโยชน์ในการรักษาผู้ที่เมื่อ hashing เป็นเพียง hashing เส้นทาง 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);
}
Math.imul
สามารถใช้สำหรับขั้นตอนการคูณซึ่งช่วยเพิ่มประสิทธิภาพการทำงาน ปัญหาเดียวคือมันจะไม่ทำงานใน IE11 โดยไม่ต้องชิม
รวดเร็วและรัดกุมซึ่งดัดแปลงมาจากที่นี่ :
String.prototype.hashCode = function() {
var hash = 5381, i = this.length
while(i)
hash = (hash * 33) ^ this.charCodeAt(--i)
return hash >>> 0;
}
ฉันต้องการฟังก์ชั่นที่คล้ายกัน (แต่แตกต่างกัน) เพื่อสร้าง 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: สำหรับรหัสใหม่ฉันใช้ shortid: https://www.npmjs.com/package/shortid
หนึ่งซับ (ยาวมาก) ของฉันเร็วโดยใช้Multiply+Xor
วิธีการของ FNV :
my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);
ฉันไม่ได้ใช้ภาษาฝั่งเซิร์ฟเวอร์ดังนั้นฉันจึงไม่สามารถทำเช่นนั้นได้
คุณแน่ใจว่าคุณไม่สามารถทำมันด้วยวิธีการที่ ?
คุณลืมไปหรือเปล่าว่าคุณกำลังใช้ 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.")));
})();
ฉันค่อนข้างช้าไปงานปาร์ตี้ แต่คุณสามารถใช้โมดูลนี้: crypto :
const crypto = require('crypto');
const SALT = '$ome$alt';
function generateHash(pass) {
return crypto.createHmac('sha256', SALT)
.update(pass)
.digest('hex');
}
ผลลัพธ์ของฟังก์ชันนี้คือ64
สตริงอักขระเสมอ บางสิ่งเช่นนี้"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"
ฉันได้รวมทั้งสองโซลูชัน (ผู้ใช้ esmiralha และ lordvlad) เพื่อรับฟังก์ชั่นที่ควรจะเร็วกว่าสำหรับเบราว์เซอร์ที่รองรับการลดฟังก์ชั่น js ()และยังเข้ากันได้กับเบราว์เซอร์รุ่นเก่า:
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();
หากคุณต้องการหลีกเลี่ยงการชนคุณอาจต้องการใช้แฮชที่ปลอดภัยเช่นSHA-256 SHA-256มีการปรับใช้ JavaScript SHA-256 หลายอย่าง
ฉันเขียนการทดสอบเพื่อเปรียบเทียบการปรับใช้แฮชหลายตัวให้ดูที่https://github.com/brillout/test-javascript-hash-implementations https://github.com/brillout/test-javascript-hash-implementations
หรือไปที่ http://brillout.github.io/test-javascript-hash-implementations/เพื่อทำการทดสอบ
นี่ควรเป็นแฮชที่มีความปลอดภัยมากกว่าคำตอบอื่น ๆ แต่ในฟังก์ชั่นโดยไม่มีแหล่งที่โหลดไว้ล่วงหน้า
ฉันสร้างsha1 เวอร์ชันย่อแบบย่อ
คุณใช้จำนวนไบต์ของสตริงและจัดกลุ่มตาม "คำ" 4 ถึง 32 บิต
จากนั้นเราจะขยายทุก 8 คำเป็น 40 คำ (เพื่อให้ได้ผลลัพธ์ที่ดีขึ้น)
สิ่งนี้จะไปที่ฟังก์ชั่นการแฮช (การลดครั้งสุดท้าย) ซึ่งเราทำการคำนวณทางคณิตศาสตร์กับสถานะปัจจุบันและอินพุต เรามักจะได้ 4 คำออกมา
นี่เป็นเวอร์ชันเกือบหนึ่งคำสั่ง / หนึ่งบรรทัดโดยใช้แผนที่ลด ... แทนที่จะเป็นลูป แต่ก็ยังค่อนข้างเร็ว
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"
ฉันไปเพื่อการเรียงต่อกันแบบง่ายของรหัส char ที่แปลงเป็นสตริงฐานสิบหก สิ่งนี้ทำหน้าที่ในวัตถุประสงค์ที่ค่อนข้างแคบนั่นคือเพียงแค่ต้องการการแทนค่าแฮชของสตริง 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('');
}
สิ่งนี้สามารถทำเพิ่มเติมสั้นและทนต่อเบราว์เซอร์ด้วยขีดล่าง ตัวอย่าง:
"Lorem Ipsum".hash()
"4c6f72656d20497073756d"
ฉันคิดว่าถ้าคุณต้องการแฮชสตริงขนาดใหญ่ในแบบเดียวกันคุณก็สามารถลดรหัส char และทำให้ผลรวมที่เกิดขึ้นไม่ใช่การรวมตัวอักขระแต่ละตัวเข้าด้วยกัน:
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"
มีความเสี่ยงต่อการชนกันมากขึ้นด้วยวิธีนี้แม้ว่าคุณจะเล่นซอกับเลขคณิตในการลดลง แต่คุณต้องการกระจายและยืดแฮชให้ยาวขึ้น
เวอร์ชันที่เรียบง่ายของคำตอบของ @ 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;
}
การเพิ่มสิ่งนี้เพราะยังไม่มีใครทำและดูเหมือนว่าจะถูกขอและดำเนินการจำนวนมากด้วยแฮช แต่มันก็ทำได้ไม่ดีนัก ...
การดำเนินการนี้จะป้อนสตริงและจำนวนสูงสุดที่คุณต้องการแฮชให้เท่ากันและสร้างหมายเลขเฉพาะตามอินพุตสตริง
คุณสามารถใช้สิ่งนี้เพื่อสร้างดัชนีที่ไม่ซ้ำกันลงในอาร์เรย์ของภาพ (ถ้าคุณต้องการส่งคืนอวาตาร์เฉพาะสำหรับผู้ใช้โดยเลือกแบบสุ่ม แต่เลือกตามชื่อของพวกเขาด้วยดังนั้นมันจะถูกกำหนดให้กับคนที่มีชื่อนั้นเสมอ )
นอกจากนี้คุณยังสามารถใช้สิ่งนี้เพื่อส่งดัชนีกลับคืนสู่อาร์เรย์ของสีเช่นการสร้างสีพื้นหลังประจำตัวที่ไม่ซ้ำใครตามชื่อของใครบางคน
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);
}
ฉันไม่เห็นเหตุผลใด ๆ ที่จะใช้รหัส crypto ที่ซับซ้อนแทนการใช้โซลูชันที่พร้อมใช้งานเช่นไลบรา Object-hash หรืออื่น ๆ การพึ่งพาผู้ขายนั้นมีประสิทธิผลมากกว่าประหยัดเวลาและลดค่าบำรุงรักษา
เพียงใช้https://github.com/puleos/object-hash
var hash = require('object-hash');
hash({foo: 'bar'}) // => '67b69634f9880a282c14a0f0cb7ba20cf5d677e9'
hash([1, 2, 2.718, 3.14159]) // => '136b9b88375971dff9f1af09d7356e3e04281951'
var crypto = require('crypto');
. ฉันคิดว่ามันเพิ่มรหัสอ้างอิงนี้จากผู้จำหน่ายในเวอร์ชันย่อระหว่างการสร้าง