문자열을 해시 형태로 변환해야합니다. 이것이 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
로 생성 된 출력 ((hash<<5)-hash)+char
은 매우 긴 문자열 (100 만 자 이상을 포함하는 문자열로 테스트 한 경우)에서도 시프트 기반 코드로 생성 된 출력과 동일 하므로 용어로 "사용할 수 없음" 정확성. 숫자 기반 버전과 시프트 기반 버전 모두에서 복잡성은 O (n)이므로 복잡성 측면에서 "사용할 수 없습니다".
n
가장 큰 문자열은 무엇 n
입니까?
var hashCode = function hashCode (str) {etc...}
? 그런 다음 hashCode("mystring")
?
편집하다
내 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)
참고 : 최상의 32 비트 해시라도 조만간 충돌 이 발생합니다.
해시 충돌 probablility은 다음과 같이 계산 될 수 로 aproximated, ( 여기 참조 ). 이는 직감이 제안한 것보다 높을 수 있습니다
. 32 비트 해시 및 k = 10,000 항목을 가정하면 확률 1.2 %로 충돌이 발생합니다. 77,163 개의 샘플에서 확률은 50 %가됩니다! ( 계산기 ).
하단에 해결 방법을 제안합니다.
이 질문에 대한 답변으로
고유성과 속도에 가장 적합한 해싱 알고리즘은 무엇입니까? Ian Boyd는 심층 분석 결과를 올렸다 . 한마디로 (내가 해석 한대로), 그는 Murmur가 최고라는 결론에 도달 한 다음 FNV-1a를 따릅니다.
esmiralha가 제안한 Java의 String.hashCode () 알고리즘은 DJB2의 변형 인 것 같습니다.
여기에 큰 입력 문자열 일부 벤치 마크 : http://jsperf.com/32-bit-hash
때 짧은 입력 문자열을 해시, DJ2B 및 FNV-1A에 비해 잡음의 성능 방울 : http://jsperf.com/32- 비트 해시 / 3
따라서 일반적으로 murmur3을 권장합니다.
JavaScript 구현에 대해서는 여기를 참조하십시오 :
https://github.com/garycourt/murmurhash-js
입력 문자열이 짧고 분배 품질보다 성능이 더 중요한 경우, esmiralha의 승인 된 답변에서 제안한대로 DJB2를 사용하십시오.
품질과 작은 코드 크기가 속도보다 중요한 경우 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
기능을 사용하여 구현할 때 FNV1a가 매우 빠를 수 있다고 합니다. 이것만으로도 최고의 벤치 마크가되며 결국 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 += ""
발생하는 예외를 피하기 위해 해싱 전에 추가 한 공유 주셔서 감사합니다str.split is not a function
hash |= 0
32 비트 int로 변환하는 데 사용 됩니다. 이 구현은 그렇지 않습니다. 이것이 버그입니까?
답변의 거의 절반은 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}
그런데, better- 여기의 뭔가의 밖으로 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 비트 해시 (2 개의 상관되지 않은 32 비트 해시 병렬)이지만 JavaScript는 53 비트 정수로 제한됩니다. 필요한 경우 16 진 문자열 또는 배열의 리턴 라인을 변경하여 완전한 64 비트 출력을 계속 사용할 수 있습니다 .
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}
ch
초기화 되나요?
'imul'
.
그것이 누군가에게 도움이된다면, 상위 2 개의 답변을 구식 브라우저 허용 버전으로 결합 reduce
했습니다.
/**
* @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의 예제 덕분에 FNV-1a에 대해 C # AND Javascript에서 동일한 결과를 얻는 방법을 찾았습니다. 유니 코드 문자가 있으면 성능 향상을 위해 상단 부분이 삭제됩니다. 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());
}
자바 스크립트 버전
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);
}
사용자 이름과 현재 시간을 기반으로 고유 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
서버 측 언어를 사용하지 않으므로 그렇게 할 수 없습니다.
당신은 확실히 당신은 그것을 할 수없는 그런 식으로 ?
진화하는 언어 인 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 기능 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();
충돌을 피하려면 SHA-256 과 같은 보안 해시 를 사용하십시오 . 몇 가지 JavaScript SHA-256 구현이 있습니다.
여러 해시 구현을 비교하는 테스트를 작성했습니다 ( https://github.com/brillout/test-javascript-hash-implementations 참조) .
또는 http://brillout.github.io/test-javascript-hash-implementations/ 로 이동 하여 테스트를 실행하십시오.
이것은 다른 답변보다 약간 더 안전한 해시이어야하지만 미리로드 된 소스가없는 함수
기본적으로 단순화 된 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("");
};
또한 단어 배열 대신 문자열을 얻기 위해 출력을 16 진수로 변환합니다.
사용법이 간단합니다. expample "a string".hash()
반환합니다"88a09e8f9cc6f8c71c4497fbb36f84cd"
16 진수 문자열로 변환 된 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('');
}
Underscore를 사용하면 더 간결하고 브라우저에 잘 견딜 수 있습니다. 예:
"Lorem Ipsum".hash()
"4c6f72656d20497073756d"
비슷한 방식으로 더 큰 문자열을 해시하려면 개별 문자를 함께 연결하는 대신 문자 코드를 줄이고 결과 합계를 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"
자연스럽게이 방법과 충돌 할 위험이 있지만 감소의 산술을 피할 수는 있지만 해시를 다양 화하고 길게하고 싶었습니다.
아직 아무도 없기 때문에 이것을 추가하면 해시로 많은 것을 요청하고 구현하는 것처럼 보이지만 항상 매우 좋지 않습니다.
이것은 문자열 입력과 해시와 같을 최대 수를 취하고 문자열 입력에 따라 고유 한 숫자를 생성합니다.
이를 사용하여 이미지 배열로 고유 한 인덱스를 생성 할 수 있습니다 (사용자에 대해 특정 아바타를 반환하고 임의로 선택했지만 이름을 기준으로 선택한 경우 항상 해당 이름을 가진 사람에게 할당됩니다) ).
물론 이것을 사용하여 다른 사람의 이름을 기반으로 고유 한 아바타 배경색을 생성하는 것과 같이 색인을 여러 색상으로 반환 할 수도 있습니다.
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);
}
객체 해시 라이브러리 등과 같은 즉시 사용 가능한 솔루션 대신이 복잡하고 복잡한 암호화 코드를 사용해야 할 이유가 없습니다. 공급 업체에 의존하는 것이 더 생산적이고 시간을 절약하며 유지 관리 비용을 절감합니다.
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');
. 빌드 중에 축소 버전으로 공급 업체 의이 종속성 코드를 추가한다고 생각합니다.