web-dev-qa-db-ja.com

小さなUrlのような、短いハッシュを作成する最良の方法は何ですか?

現在、MD5ハッシュを使用していますが、[a-z] [A-Z] [0-9]のみを使用する短いハッシュを作成するものを見つけたいと思います。長さは5〜10文字程度で十分です。

すでにこれを行う何かがありますか?

更新:

CRC32ハッシュが好きです。 .NETでそれを計算するきれいな方法はありますか?

pdate2:

Joeが提供したリンクからCRC32関数を使用しています。 uIntを上記で定義した文字に変換するにはどうすればよいですか?

42
Arron S

.NET文字列オブジェクトにはGetHashCode()関数があります。整数を返します。 16進数に変換してから、8文字の文字列に変換します。

そのようです:

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

その詳細: http://msdn.Microsoft.com/en-us/library/system.string.gethashcode.aspx

UPDATE:この回答に上記のリンクからのコメントを追加しました:

GetHashCodeの動作は、その実装に依存します。これは、共通言語ランタイムのバージョンごとに異なる場合があります。これが発生する理由は、GetHashCodeのパフォーマンスを向上させるためです。

2つの文字列オブジェクトが等しい場合、GetHashCodeメソッドは同じ値を返します。ただし、一意の文字列値ごとに一意のハッシュコード値はありません。 異なる文字列は同じハッシュコードを返すことができます。

発信者への注意

GetHashCodeによって返される値はplatform-dependentです。 .NET Frameworkの32ビットバージョンと64ビットバージョンでは異なります。

50
Vlad

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)。

34

URL短縮サービスはハッシュを使用するとは思わない。新しいURLごとに増加し、データベースに保存される実行中の英数字文字列があるだけだと思う​​。本当にハッシュ関数を使用する必要がある場合は、次のリンクを参照してください。 一部のハッシュ関数コーディングホラー記事

16
jörg

エントリの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では大文字と小文字が区別されます。あなたはまだあなたのニース、きちんとした英数字キーを取得し、衝突がないことを保証して見ることができます!

11
KingNestor

ショートバージョンから実際の値への1対1のマッピングが必要なため、shortハッシュを使用できません。短いハッシュの場合、衝突の可能性は非常に高くなります。通常の長いハッシュはあまりユーザーフレンドリーではありません(そして、衝突の可能性はおそらく十分に小さいかもしれませんが、それでも私にとって「正しい」とは感じません)。

TinyURL.com 使用するようですBase 36 (0-9、A-Z)に変換されるインクリメントされた数値。

7
Arjan

まず、ランダムな個別番号のリストを取得します。次に、基本文字列から各charを選択し、結果を追加して返します。 5文字を選択しています。これは、ベース62から6471002の順列になります。2番目の部分は、短いURLを保存しない場合、存在するかどうかをdbで確認することです。

 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));
      } 
  }
3

英数字としてエンコードすることにより、MD5ハッシュの文字数を減らすことができます。通常、各MD5文字は16進数として表されるため、16の可能な値です。 [a-zA-Z0-9]には62の可能な値が含まれているため、4つのMD5値を取得して各値をエンコードできます。

編集:

これは、数値(4桁の16進数)を取り、[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';
}
3
Colin

CRC32を使用できます。CRC32は8バイト長で、MD5に似ています。タイムスタンプを実際の値に追加することにより、一意の値がサポートされます。

そのため、 http://foo.bar/abcdefg12 のようになります。

2
Joe

Intersから小さなユニークなハッシュを生成するライブラリを探しているなら、 http://hashids.org/net/ を強くお勧めします。私は多くのプロジェクトでそれを使用し、素晴らしく機能します。カスタムハッシュに独自の文字セットを指定することもできます。

2
herostwist

Md5ハッシュコードを16進数ではなくbase64でエンコードすることもできます。この方法では、文字[a-z] [A-Z] [0-9]を使用して短いURLを取得できます。

0
codymanix

btoa と呼ばれるすばらしいが古代のプログラムがあります。これは、バイナリをASCIIに大文字、小文字、数字、2つの追加文字を使用して変換します。 MIME base64エンコーディングもあります;ほとんどのLinuxシステムには、おそらくbase64またはbase64encodeと呼ばれるプログラムがあります。どちらも32ビットCRCから読み取り可能な短い文字列を提供します。

0
Norman Ramsey

暗号強度を気にしない場合は、CRC関数のいずれかが実行されます。

Wikipedia は、出力の長さなど、さまざまなハッシュ関数のリストを表示します。出力を[a-z] [A-Z] [0-9]に変換するのは簡単です。

0
Kevin Montrose