hash 在Javascript / jQuery中从字符串生成一个哈希
编辑
基于我的jsperf测试,接受的答案实际上更快: http://jsperf.com/hashcodelordvlad ://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);
}
我需要将字符串转换为某种形式的散列。 这是可能的JavaScript / jQuery?
我没有使用服务器端语言,所以我不能这样做。
基于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!'));
这是一个精致,性能更好的变体:
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()
的实现相匹配。
这里也是一个只返回肯定hashcode的文件:
String.prototype.hashcode = function() {
return (this.hashCode() + 2147483647) + 1;
};
这里有一个匹配的Java,它只返回肯定的hashcode:
public static long hashcode(Object obj) {
return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}
请享用!
感谢mar10的例子,我发现了一种在C#和Javascript中为FNV-1a获得相同结果的方法。 如果存在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);
}
一个从here改编的快速简洁的文章:
String.prototype.hashCode = function() {
var hash = 5381, i = this.length
while(i)
hash = (hash * 33) ^ this.charCodeAt(--i)
return hash >>> 0;
}
我已经将两个解决方案(用户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/ ,运行测试。
通过这个解决方案,我们可以指定字符集以避免在应用程序层之间存储或发送值时出现一些问题,例如:当结果字符串(哈希)产生百分比编码并且该字符串从视图中使用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
}