52

我目前正在使用 MD5 哈希,但我想找到一些可以创建更短的哈希的东西,它只使用[a-z][A-Z][0-9]. 它只需要大约 5-10 个字符长。

有什么东西已经这样做了吗?

更新1:

我喜欢CRC32哈希。在.NET中是否有一种干净的计算方法?

更新 2:

我正在使用Joe提供的链接中的CRC32函数。如何将 uInt 转换为上面定义的字符?

4

14 回答 14

59

.NET 字符串对象有一个 GetHashCode() 函数。它返回一个整数。将其转换为十六进制,然后转换为 8 个字符长的字符串。

像这样:

string hashCode = String.Format("{0:X}", sourceString.GetHashCode());

更多信息:http: //msdn.microsoft.com/en-us/library/system.string.gethashcode.aspx

更新:将上述链接中的备注添加到此答案:

GetHashCode 的行为取决于它的实现,它可能会从公共语言运行时的一个版本更改为另一个版本。发生这种情况的一个原因是为了提高 GetHashCode 的性能。

如果两个字符串对象相等,则 GetHashCode 方法返回相同的值。但是,每个唯一的字符串值都没有唯一的哈希码值。不同的字符串可以返回相同的哈希码。

来电者须知

GetHashCode 返回的值是平台相关的。它在 .NET Framework 的 32 位和 64 位版本上有所不同。

于 2012-01-11T18:52:52.197 回答
37

您的目标是创建 URL 缩短器还是创建哈希函数?

如果您的目标是创建 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);
}

使用加密数字生成器将使人们很难预测您生成的字符串,我认为这对您很重要。

然后,您可以使用字母表中的字符将 8 字节随机数转换为字符串。这基本上是基数计算的变化(从基数 256 到基数 62)。

于 2009-07-12T22:24:58.577 回答
17

我不认为 URL 缩短服务使用哈希,我认为它们只是有一个运行的字母数字字符串,随着每个新 URL 的增加并存储在数据库中。如果您真的需要使用哈希函数,请查看此链接:一些哈希函数 另外,有点离题,但取决于您正在处理的内容,这可能会很有趣:编码恐怖文章

于 2009-07-12T20:45:01.167 回答
13

只需取条目 ID 的 Base36(不区分大小写)或 Base64。

所以,假设我想使用 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 将区分大小写。您可以看到您仍然得到漂亮、整洁的字母数字密钥,并且保证不会发生冲突!

于 2009-07-13T01:04:56.987 回答
7

您不能使用散列,因为您需要从短版本到实际值的一对一映射。对于短散列,发生冲突的机会太高了。正常的长散列不会对用户非常友好(即使那时发生冲突的机会可能足够小,我仍然不会觉得“正确”)。

TinyURL.com似乎使用转换为Base 36 (0-9, AZ) 的递增数字。

于 2009-07-12T21:06:39.953 回答
3

您可以通过将 MD5 哈希编码为字母数字来减少字符数。每个 MD5 字符通常表示为十六进制,因此有 16 个可能的值。[a-zA-Z0-9] 包含 62 个可能的值,因此您可以通过获取 4 个 MD5 值来对每个值进行编码。

编辑:

这是一个函数,它接受一个数字(4 个十六进制数字长)并返回 [0-9a-zA-Z]。这应该让您了解如何实现它。请注意,类型可能存在一些问题;我没有测试这段代码。

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';
}
于 2009-07-12T20:45:07.703 回答
3

首先,我得到一个随机不同数字的列表。然后我char从基本字符串中选择每个,追加并返回结果。我选择了 5 个字符,这将相当于 62 个基数中的 6471002 个排列。第二部分是检查 db 以查看是否存在,如果不保存短 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));
      } 
  }
于 2012-09-23T16:47:27.847 回答
2

您可以使用 CRC32,它有 8 个字节长,类似于 MD5。将时间戳添加到实际值将支持唯一值。

所以它看起来像http://foo.bar/abcdefg12

于 2009-07-12T20:41:32.110 回答
2

如果您正在寻找一个从 inters 生成微小唯一哈希的库,我强烈推荐http://hashids.org/net/。我在许多项目中使用它,并且效果非常好。您还可以为自定义哈希指定自己的字符集。

于 2015-11-11T10:44:38.977 回答
0

如果您不关心加密强度,任何 CRC 函数都可以。

维基百科列出了一堆不同的散列函数,包括输出长度。将它们的输出转换为 [az][AZ][0-9] 是微不足道的。

于 2009-07-12T20:43:23.837 回答
0

您可以使用 base64 而不是十六进制对 md5 哈希码进行编码,这样您就可以使用字符 [az][AZ][0-9] 获得更短的 url。

于 2009-07-12T21:42:07.260 回答
0

有一个奇妙但古老的程序btoa,它使用大小写字母、数字和两个附加字符将二进制转换为 ASCII。还有 MIME base64 编码;大多数 Linux 系统可能都有一个名为base64or的程序base64encode。任何一个都会为您提供一个来自 32 位 CRC 的简短、可读的字符串。

于 2009-07-13T00:28:16.900 回答
-1

您可以获取 MD5 哈希的前 5-10 个字母数字字符。

于 2009-07-12T20:42:08.520 回答
-1

如果您需要在每次调用时更改哈希值,您可以执行以下操作:

string hash = String.Format("{0:X}", DateTime.Now.GetHashCode());
于 2021-10-27T19:03:18.863 回答