web-dev-qa-db-ja.com

文字列から一意の整数ハッシュ

文字列を一意の整数値に変更できるシステムを開発しようとしています。たとえば、「アカウント」という単語の暗号化された数値は0891で、同じ変換プロセスで他のWordを0891に変換することはできません、それはnotを行いますが、生成された整数を文字列に変換できるようにする必要があります。

同時に、単語の構造規則に依存します。つまり、「精度」や「お知らせ」などの単語の生成数は0891を超え、「a」、「abacus」、「略語」などの単語は生成された数値は0891未満です。

このアプリケーションの目的は、インデックスまたは主キーと同様に機能することです。増分インデックスを使用していない理由は、セキュリティ上の理由からであり、セット内のデータ数に対するインデックスの依存関係が原因です。

(例えば。)

[0] A, [1] B, [2] C, [3] D, [4] E, [5] F

上記の文字にはそれぞれ対応するインデックスがあり、Eには4のインデックスがあります

ただし、データが突然増加または減少した場合、ソートされます

[0] A, [1] AA, [2] AAB, [3] C, [4] D, [5] DA, [6] DZ, [7] E, [8] F

Eのインデックスは7になりました

各Wordには一意の独立した積分等価物が必要であり、対応する重みがあります。

上記を実行できるアルゴリズムが存在するかどうかを知る必要があります。

どんな助けも感謝します。

17
Treize

これは、最大長を課さない限り、指定した制約では不可能です。

k("a")k("b")がこれら2つの文字列のコードであると仮定します。

制約では、これら2つの値の間にある一意の整数値を探していますが、k("a") < k("a....a") < k("b")です。 2つのコードの間に収まる必要があるスタイル"a....a"(および"akjhdsfkjhs")の文字列は無限にあるため、order preserving general、unique、fixed-任意の長さの文字列には長さコードは存在できません。文字列と同数の整数が必要になるため、また文字列は長さに制限されていないため、これは機能しません。

一般(新しい文字列の挿入を許可しない)、一意(衝突を許可する-たとえば、最初の4文字をコードとして使用してください!)、無制限の長さ(たとえば3文字まで)、または順序を維持するプロパティをドロップします。

10
Erich Schubert

簡単にするために、aからzまでが単語で許可されている唯一の文字であると仮定します。

長さ2文字列までの番号を割り当てましょう:

_String Value
a      0
aa     1
ab     2
...
az     26
b      27
ba     28
bb     29
...
bz     53
c      54
...
_

これを見るだけで、特定の短い文字列のオフセットを決定するには、許可されている最大長が必要であることを理解できるはずです。この番号を知っていると仮定しましょう。

アルゴリズムを簡単にするために、27から開始することをお勧めします:(0から開始する場合は、自由に考えてみてください。特別なケースが必要になります)

_String Value
a      27
aa     28
ab     29
...
_

したがって、本質的に、左端の文字は値27*(1-26)(azの場合)に寄与し、右側の次の文字(存在する場合)はaの値に_1-26_(azの場合)を寄与しますストリング。

これは、左端の数字が_(1-26)*27^(len-1)_、次の_(1-26)*27^(len-2)_などのように_(1-26)*27^0_まで貢献すると言うために一般化できます。

Javaコード:

_long result = 0;
for (int i = 0; i < s.length(); i++)
   result += pow(27, MAX_LENGTH - i - 1)*(1 + s.charAt(i) - 'a');
_

テスト出力:

_a                    =   150094635296999121
aa                   =   155653695863554644
aaa                  =   155859586995649293
aaaa                 =   155867212593134280
aaaaa                =   155867495022670761
abacus               =   161447654121636735
abbreviation         =   161763445236432690
account              =   167509959568845165
accuracy             =   167554723653128367
announcement         =   230924421746611173
z                    =  3902460517721977146
_

オンラインデモ

はい、それらは長さ13文字列までのかなり大きな数字ですが、実際の辞書の単語に連続して番号を割り当てないと、それ以上のことはできません(ただし、0から開始する、つまり比較的話す、わずかな違い)、文字シーケンスには多くの可能性があるためです。

8
Dukeling

一意性のために、文字に素数を割り当てることから始めます:A -> 2, B -> 3, C -> 5, D -> 7など.

Wordの特定の文字の「キー」を計算するには、Wordの位置インデックスの累乗を累乗します。 Word全体の「キー」を取得するには、すべての文字キーを乗算します。

たとえば、Word CAB:

C -> 5 ^ 1 = 5
A -> 2 ^ 2 = 4
B -> 3 ^ 3 = 81
CAB -> 5 * 4 * 81 =  1620.

1620を他のWordがキーとして与えることはありません。

注:マッピングを追跡する限り、A-> 2で開始したり、アルファベットの文字に素数を割り当てたりする必要はありません。また、この結果はすぐに大きくなることに注意してください。

ただし、セキュリティに関する他のコメントに留意してください。これは特に安全なアルゴリズムではありません。

3
Vicky

これらの整数が占めることができるバイト数に制限がない場合、各文字の基礎となる(たとえば、Ascii)バイトコードは整数表現を提供します。同様に、0 = A、1 = BからZ = 25までを割り当てると、Word自体は基数26の整数になります。

2
Stochastically

あなたはこれを行うことができます:

SEPARETOR = '000'
string_to_hash = "some_string"
hashed_result = int(SEPARETOR.join(list(str(ord(character)) for character in string_to_hash)))

楽しい!

1
Yuval Pruss

昇順で各アルファベットに一意の素数を割り当てます(順序は不要です)。

注意してください:素数の乗算はこれらの数値でのみ乗算できる一意の結果であるため、各Wordに一意の値を与えます。

アルゴリズム:

int hash = 0;
forEach (int i = 0 ; i < Word.length ; i++)
{ 
   hash *= (prime[c[i]] ** (length - i)); 
}

prime-それぞれに対応する素数を格納する配列

(文字列-1)に電力を供給して、この文字が発生する場所に値を与えて辞書の順序を維持します。

このアルゴリズムは、十分に大きな値を与えます-= オーバーランあなたの配列。

また、単語の長さが短いほど、長さが長い単語よりも値が低くなり、辞書の順序に影響する可能性がありますしかし、一意性がここで維持されるため、辞書の順序が必要な理由はわかりません。

1
Rahul

はい、しかしほとんどはありません。

はい、確率論的答えのように。基数26(またはすべてのASCIIの基数128)を設定することにより、理論的に各文字列を一意にハッシュできます。

一方、これは非現実的であり、ほとんどの言語にとって数値が大きくなりすぎるだけでなく、これは信じられないほど消費の多いプロセスです。さらに、文字列を無限にすることができる場合、 Cantorの対角引数 の形式を適用して、このアルゴリズムを「破る」こともできます。カーディナリティaleph-one(文字列)のセットからカーディナリティaleph-null(int)のセットへの1対1マッピングを作成することはできません。

0
tox123