什么是创build一个简短的散列最好的方法,类似于小的Url做什么?
我目前正在使用MD5散列,但我想find一些将使用只是[az] [AZ] [0-9]更短的散列。 它只需要大约5-10个字符。
有没有这样的东西呢?
更新:
我喜欢CRC32哈希。 有没有一种干净的方式来计算它在.NET中?
UPDATE2:
我使用Joe提供的链接的CRC32function。 如何将uInt转换为上面定义的字符?
.NETstring对象有一个GetHashCode()函数。 它返回一个整数。 将其转换为hex,然后转换为长度为8个字符的string。
像这样:
string hashCode = String.Format("{0:X}", sourceString.GetHashCode());
更多有关: http : //msdn.microsoft.com/en-us/library/system.string.gethashcode.aspx
更新:添加上面的链接到这个答案的评论:
GetHashCode的行为依赖于它的实现,这可能会从公共语言运行时的一个版本改变到另一个版本。 这可能发生的原因是为了提高GetHashCode的性能。
如果两个string对象相等,则GetHashCode方法返回相同的值。 但是,每个唯一string值都没有唯一的哈希码值。 不同的string可以返回相同的哈希码。
给呼叫者的提示
GetHashCode返回的值是平台相关的 。 它在.NET Framework的32位和64位版本上有所不同。
你的目标是创build一个URL缩短或创build一个哈希函数?
如果你的目标是创build一个URL缩短器,那么你不需要一个哈希函数。 在这种情况下,您只需要预先生成一系列密码安全的随机数字,然后为每个url分配一个唯一编号。
您可以使用如下代码来完成此操作:
using System.Security.Cryptography; const int numberOfNumbersNeeded = 100; const int numberOfBytesNeeded = 8; var randomGen = RandomNumberGenerator.Create(); for (int i = 0; i < numberOfNumbersNeeded; ++i) { var bytes = new Byte[numberOfBytesNeeded]; randomGen.GetBytes(bytes); }
使用密码数字生成器将使人们很难预测你生成的string,我认为这对你很重要。
然后可以使用字母表中的字符将8字节随机数转换为string。 这基本上是基数计算的变化(从基数256到基数62)。
我不认为url缩短服务使用散列,我想他们只是有一个运行的字母数字string,每增加一个新的URL并存储在数据库中。 如果你真的需要使用散列函数,请看这个链接: 一些散列函数也有点偏离主题,但取决于你在做什么这可能是有趣的: 编码恐怖文章
只需要一个Base36(不区分大小写)或Base64的条目的ID。
所以,可以说我想使用Base36:
(ID – Base36)
1 – 1
2 – 2
3 – 3
10 – A
11 – B
12 – C
…
10000 – 7PS
22000 – GZ4
34000 – Q8C
…
1000000 – LFLS
2345000 – 1E9EW
6000000 – 3KLMO
如果你使用base64,那么你可以保持这些更短,但是这个URL是区分大小写的。 你可以看到你仍然得到你的漂亮,整齐的字母数字键,并保证不会有碰撞!
您不能使用短散列,因为您需要从短版本到实际值的一对一映射。 对于一个简短的散列来说,碰撞的机会将会非常高。 正常的,长时间的哈希,不会很人性化(即使碰撞的机会可能足够小,那么对我来说也不会觉得“正确”)。
TinyURL.com 似乎使用一个递增的数字转换为基地36 (0-9,AZ)。
您可以通过将其编码为字母数字来减lessMD5哈希中的字符数。 每个MD5字符通常表示为hex,所以这是16个可能的值。 [a-zA-Z0-9]包含62个可能的值,所以你可以通过取4个MD5值来编码每个值。
编辑:
这是一个函数,它需要一个数字(4个hex数字)并返回[0-9a-zA-Z]。 这应该给你一个如何实现它的想法。 请注意,types可能存在一些问题; 我没有testing这个代码。
char num2char( unsigned int x ){ if( x < 26 ) return (char)('a' + (int)x); if( x < 52 ) return (char)('A' + (int)x - 26); if( x < 62 ) return (char)('0' + (int)x - 52); if( x == 62 ) return '0'; if( x == 63 ) return '1'; }
您可以使用CRC32,长度为8个字节,与MD5类似。 将时间戳添加到实际值将支持唯一值。
所以它会看起来像http://foo.bar/abcdefg12 。
首先我得到一个随机不同的数字列表。 然后我从基本string中select每个char
,追加并返回结果。 我select5个字符,这将相当于6471002排列基地62.第二部分是检查数据库,看看是否存在,如果没有保存短的url。
const string BaseUrlChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static string ShortUrl { get { const int numberOfCharsToSelect = 5; int maxNumber = BaseUrlChars.Length; var rnd = new Random(); var numList = new List<int>(); for (int i = 0; i < numberOfCharsToSelect; i++) numList.Add(rnd.Next(maxNumber)); return numList.Aggregate(string.Empty, (current, num) => current + BaseUrlChars.Substring(num, 1)); } }
如果你正在寻找一个图书馆,从inters间生成微小独特的哈希,我可以强烈推荐http://hashids.org/net/ 。 我在许多项目中使用它,它运作得非常好。 你也可以为自定义散列指定自己的字符集。
如果你不关心encryption强度,任何CRC函数都可以。
维基百科列出了一堆不同的哈希函数,包括输出的长度。 转换他们的输出到[az] [AZ] [0-9]是微不足道的。
你可以使用base64而不是hex来编码你的md5哈希码,这样你就可以使用字符[az] [AZ] [0-9]来得到更短的URL。
有一个奇妙而古老的btoa
程序,它使用大写和小写字母,数字和两个附加字符将二进制转换为ASCII。 还有MIME base64编码; 大多数Linux系统可能有一个名为base64
或base64encode
的程序。 任何一个人都会给你一个32位的CRC校验码。
您可以采用MD5散列的第一个字母数字5-10个字符。