私はドキュメント名をキーとしたいくつかのデータリストを扱っています。文書名は、非常にわかりやすいですが、表示する必要がある場合は非常に扱いにくく(最大256バイトまではかなりの面積です)、必要に応じて簡単に再現できる小さなキーフィールドを作成できるようにしたいです。他のワークシートまたはワークブックからVLOOKUP
を実行する。
タイトルごとに一意で再現可能なハッシュを各タイトルが最も適切になると考えています。利用可能な機能はありますか、それとも私は自分自身のアルゴリズムの開発を検討していますか?
これや他の戦略について何か考えやアイデアはありますか?
あなたはあなた自身の関数を書く必要はありません - 他の人がすでにあなたのためにそれをしました。
例えば、私はこの stackoverflow answerに対して5つのVBAハッシュ関数を集めて比較しました
私は個人的にこのVBA機能を使っています
=BASE64SHA1(A1)
で呼び出されますPublic Function BASE64SHA1(ByVal sTextToHash As String)
Dim asc As Object
Dim enc As Object
Dim TextToHash() As Byte
Dim SharedSecretKey() As Byte
Dim bytes() As Byte
Const cutoff As Integer = 5
Set asc = CreateObject("System.Text.UTF8Encoding")
Set enc = CreateObject("System.Security.Cryptography.HMACSHA1")
TextToHash = asc.GetBytes_4(sTextToHash)
SharedSecretKey = asc.GetBytes_4(sTextToHash)
enc.Key = SharedSecretKey
bytes = enc.ComputeHash_2((TextToHash))
BASE64SHA1 = EncodeBase64(bytes)
BASE64SHA1 = Left(BASE64SHA1, cutoff)
Set asc = Nothing
Set enc = Nothing
End Function
Private Function EncodeBase64(ByRef arrData() As Byte) As String
Dim objXML As Object
Dim objNode As Object
Set objXML = CreateObject("MSXML2.DOMDocument")
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.nodeTypedValue = arrData
EncodeBase64 = objNode.text
Set objNode = Nothing
Set objXML = Nothing
End Function
ハッシュ長のカスタマイズ
Const cutoff As Integer = 5
.NETを必要とせず外部ライブラリを使用しないハッシュ関数( 3つすべてのCRC16関数 )もあります。しかし、ハッシュは長くなり、衝突が増えます。
この サンプルワークブック をダウンロードして、5つすべてのハッシュ実装を試してみることもできます。ご覧のとおり、最初のシートには良い比較があります
衝突についてはあまり気にしませんが、可変長文字列フィールドに基づく行の弱い擬似ランダム化器が必要でした。これがうまくいった非常識な解決策の1つです:
=MOD(MOD(MOD(MOD(MOD(IF(LEN(Z2)>=1,CODE(MID(Z2,1,1))+10,31),1009)*IF(LEN(Z2)>=3,CODE(MID(Z2,3,1))+10,41),1009)*IF(LEN(Z2)>=5,CODE(MID(Z2,5,1))+10,59),1009)*IF(LEN(Z2)>=7,CODE(MID(Z2,7,1))+10,26),1009)*IF(LEN(Z2)>=9,CODE(MID(Z2,9,1))+10,53),1009)
Z2
はハッシュしたい文字列を含むセルです。
"MOD"は科学的表記法へのオーバーフローを防ぐためにあります。 1009
は素数で、X * 255 <max_int_size
となるように任意のXを使用できます。 10は任意です。何でも使う「その他」の値は任意です(ここではpiの桁です)。何でも使う文字の位置(1,3,5,7,9)は任意です。何でも使う.
かなり小さいリストの場合は、組み込みのExcel関数を使用してスクランブラ(貧乏人のハッシュ関数)を作成できます。
例えば。
=CODE(A2)*LEN(A2) + CODE(MID(A2,$A$1,$B$1))*LEN(MID(A2,$A$1,$B$1))
ここでA1とB1はランダムな開始文字と文字列の長さを保持します。
ちょっと手間をかけてチェックするだけで、ほとんどの場合、実行可能な固有IDを非常に素早く取得できます。
仕組み:式は、文字列の最初の文字と文字列の中央から取られた固定文字を使い、ファンニング関数としてLEN()を使います。衝突の可能性を減らすため。
注意:これはハッシュではないが、必要なときは何かを素早く終わらせるために、そして衝突がないことを確かめるために結果を調べることができるなら、それは非常にうまくいきます。
編集:あなたの文字列が可変長(例えばフルネーム)を持つべきだが固定幅フィールドを持つデータベースレコードから引き出されるなら、あなたはそれをしたいでしょう。このような:
=CODE(TRIM(C8))*LEN(TRIM(C8))
+CODE(MID(TRIM(C8),$A$1,1))*LEN(MID(TRIM(C8),$A$1,$B$1))
長さが意味のあるスクランブラになるように。
毎回スクリプトを実行しなくても衝突を防ぐことができ、かなり良い結果が得られます。 0から1の間の値が必要でした。
=ABS(COS((CODE(MID(A2,ROUNDUP(LEN(A2)/9,0),1))*(CODE(MID(A2,ROUNDUP(LEN(A2)/5,0),1))+100)/CODE(MID(A2,ROUNDUP(LEN(A2)/3,0),1))*(CODE(MID(A2,ROUNDUP(LEN(A2)*8/9,0),1))+25)/CODE(MID(A2,ROUNDUP(LEN(A2)*6/9,0),1))*(CODE(MID(A2,ROUNDUP(LEN(A2)*4/9,0),1))-25))/LEN(A2)+CODE(A2)))
文字列全体から文字を選択し、それらの文字のそれぞれの値を取り、値を加算して(同じ結果になる同じ場所にある同じ文字を防ぐため)、それぞれを乗算/除算して合計に対してCOS関数を実行します。
これを試すことができます。 2つの列で疑似#を実行します。
= + IF(AND(ISBLANK(D3)、ISBLANK(E3))、 ""、コード(TRIM(D3&E3))+コード(MID(TRIM(D3&E3)、$ A $ 1 * LEN) (D3&E3)、1))INT(LEN(TRIM(D3&E3))$ B $ 1))
A1とB1が手動で入力されたランダムシードを格納する場所:0
私の知る限りでは、ハッシュ関数はExcelに組み込まれていません - あなたはVBAのユーザー定義関数としてそれを構築する必要があるでしょう。
しかし、あなたの目的のためにはハッシュを使うことが必須ではない、あるいは本当に有利だとは思わないことに注意してください。 VLOOKUP
は256バイトでも同様に動作しますが、小さいハッシュでも同様です。確かに、それは少し遅いかもしれません - 確かにそれは計り知れないほど小さいので少しです。そしてハッシュ値を追加することはあなたにとって、そしてExcelにとってもっと手間がかかります。