Javascript의 문자열에서 해시 생성
문자열을 해시 형태로 변환해야합니다. 이것이 JavaScript에서 가능합니까?
서버 측 언어를 사용하지 않아서 그렇게 할 수 없습니다.
String.prototype.hashCode = function() {
var hash = 0, i, chr;
if (this.length === 0) return hash;
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/
편집하다
내 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 비트 해시라도 조만간 충돌 이 발생합니다.
해시 충돌 probablility은 다음과 같이 계산 될 수 로 aproximated, ( 여기 참조 ). 이는 직감이 제안한 것보다 높을 수 있습니다
. 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
입력 문자열이 짧고 분배 품질보다 성능이 더 중요한 경우, 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)
}
조심해서 사용하고 너무 많이 기대하지 마십시오.
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!'));
누군가에게 도움이된다면 상위 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 = new String("some string to be hashed").hashCode();
답변의 거의 절반은 Java 구현으로 String.hashCode
, 고품질도 빠르지도 않습니다. 너무 특별하지는 않습니다. 매번 31로 배수됩니다. 한 줄로 효율적으로 구현할 수 있으며 다음과 같이 훨씬 빠릅니다 Math.imul
.
var jhashcode=s=>{for(var i=0,h;i<s.length;i++)h=Math.imul(31,h)+s.charCodeAt(i)|0;return h}
여기 간단하고 잘 분산 된 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);
};
xxHash / MurmurHash3과 유사한 기술을 사용하지만 철저하지는 않습니다. 그것은 눈사태 (엄격하지 않음)를 달성하므로 입력의 작은 변화는 출력의 큰 변화를 가져서 무작위로 나타납니다.
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 비트를 계속 사용할 수 있습니다.
return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];
캐치는 16 진수 문자열을 구성하면 성능의 병목 현상이되고 배열에는 하나 대신 두 개의 비교 연산자가 필요하므로 편리하지 않습니다. 따라서 고성능 응용 프로그램에 사용할 때 명심하십시오.
FNV / DJB2 / SMDB를 여전히 능가하는 89 개의 문자로 된 최소 32 비트 해시가 있습니다.
TSH=s=>{for(var i=0,h=6;i<s.length;)h=Math.imul(h^s.charCodeAt(i++),9**9);return h^h>>>9}
이것은 세련되고 성능이 뛰어난 변형입니다.
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);
});
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
여기 에서 적응 한 빠르고 간결한 것 :
String.prototype.hashCode = function() {
var hash = 5381, i = this.length
while(i)
hash = (hash * 33) ^ this.charCodeAt(--i)
return hash >>> 0;
}
FNV의 Multiply+Xor
방법을 기반으로 한 빠른 (매우 긴) 라이너 :
my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);
나는 두 가지 솔루션 (사용자 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/ 로 이동 하여 테스트를 실행하십시오.
나는 파티에 늦었지만이 모듈을 사용할 수 있습니다 : crypto :
const crypto = require('crypto');
const SALT = '$ome$alt';
function generateHash(pass) {
return crypto.createHmac('sha256', SALT)
.update(pass)
.digest('hex');
}
이 함수의 결과는 항상 64
문자열입니다. 이 같은:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"
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"
자연스럽게이 방법과 충돌 할 위험이 있지만 감소의 산술을 피할 수는 있지만 해시를 다양 화하고 길게하고 싶었습니다.
@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);
}
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.")));
})();
객체 해시 라이브러리 등과 같은 즉시 사용 가능한 솔루션 대신이 복잡하게 암호화 된 암호화 코드를 사용해야하는 이유는 없습니다. 공급 업체에 의존하는 것이보다 생산적이고 시간을 절약하며 유지 보수 비용을 절감합니다.
https://github.com/puleos/object-hash를 사용 하십시오.
var hash = require('object-hash');
hash({foo: 'bar'}) // => '67b69634f9880a282c14a0f0cb7ba20cf5d677e9'
hash([1, 2, 2.718, 3.14159]) // => '136b9b88375971dff9f1af09d7356e3e04281951'
참고 URL : https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
'Programming' 카테고리의 다른 글
유효한 응답을 제공 할 때까지 사용자에게 입력 요청 (0) | 2020.02.11 |
---|---|
Docker 이미지를 컨테이너로 실행 (0) | 2020.02.11 |
파이썬이 사전에 새로운 아이템 추가 (0) | 2020.02.11 |
노드가 존재하지 않는 경우 디렉토리를 작성하는 방법은 무엇입니까? (0) | 2020.02.11 |
고정 이름이 'System.Data.SqlClient'인 ADO.NET 제공자에 대한 Entity Framework 제공자를 찾을 수 없습니다. (0) | 2020.02.11 |