Apakah ada fungsi Excel untuk membuat nilai hash?

26

Saya sedang bekerja dengan sejumlah daftar data yang dikunci dengan nama dokumen. Nama-nama dokumen, walaupun sangat deskriptif, cukup rumit jika saya perlu melihatnya (hingga 256 byte adalah banyak real estat) dan saya ingin dapat membuat keyfield yang lebih kecil yang siap direproduksi jika saya perlu untuk melakukan VLOOKUPdari workseet atau workbook lain.

Saya pikir hash dari judul yang unik dan dapat direproduksi untuk setiap judul akan lebih tepat. Apakah ada fungsi yang tersedia, atau saya melihat pengembangan algoritma saya sendiri?

Adakah pemikiran atau ide tentang ini atau strategi lain?

dwwilson66
sumber

Jawaban:

34

Anda tidak perlu menulis fungsi Anda sendiri - orang lain sudah melakukannya untuk Anda.
Sebagai contoh saya mengumpulkan dan membandingkan lima fungsi hash VBA pada jawaban stackoverflow ini

Secara pribadi saya menggunakan fungsi VBA ini

  • disebut dengan =BASE64SHA1(A1)di Excel setelah Anda menyalin makro ke modul VBA
  • memerlukan .NET karena menggunakan pustaka "Microsoft MSXML" (dengan pengikatan yang lebih lambat)

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

Menyesuaikan panjang hash

  • hash awalnya adalah string unicode panjang 28 karakter (case sensitif + karakter khusus)
  • Anda menyesuaikan panjang hash dengan baris ini: Const cutoff As Integer = 5
  • 4 digit hash = 36 tumbukan di 6895 baris = tingkat tumbukan 0,5%
  • 5 digit hash = 0 collision di 6895 baris = 0% collision rate

Ada juga fungsi hash ( ketiga fungsi CRC16 ) yang tidak memerlukan .NET dan tidak menggunakan perpustakaan eksternal. Tetapi hash lebih panjang dan menghasilkan lebih banyak tabrakan.

Anda juga bisa mengunduh contoh buku kerja ini dan bermain-main dengan semua 5 implementasi hash. Seperti yang Anda lihat ada perbandingan yang bagus di lembar pertama

nixda
sumber
1
Tampak hebat. Namun, saya tidak memiliki cukup pengalaman VBA untuk mencegah Excel kembali #NAME?. Lihat kode> potong dan tempel kode ke jendela baru - di dalam lembar kerja yang benar di navigator> simpan sebagai lembar kerja berkemampuan makro> tutup dan kembali ke excel ... hal lain yang saya lewatkan? Apakah saya perlu mengkompilasinya?
dwwilson66
Ya ... untuk memperjelas ... saya menempelkannya di jendela kode baru yang muncul ketika saya pergi ke tab lembar kerja> melihat kode ... Mengunduh sampel sekarang, tetapi saya ingin memahami mengapa excel tidak mengenali kode saya
dwwilson66
WooHoo ... lembar sampel membantu. Menyadari saya telah menempelkan kode ke dan unggul jendela OBJECT, bukan jendela MODULE. Saya mendapatkan hash di buku kerja saya sekarang!
dwwilson66
1
Ini adalah alat yang luar biasa.
Jay Killeen
1
Anda dapat membuat cutoffparameter dan opsional dengan default berbeda dengan memindahkannya ke daftar Parameter fungsi Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) dan menghapus deklarasi di dalam fungsi.
Core
9

Saya tidak terlalu peduli tentang tabrakan, tetapi membutuhkan pseudorandomizer baris yang lemah berdasarkan bidang string panjang variabel. Inilah salah satu solusi gila yang bekerja dengan baik:

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

Di mana Z2sel berisi string yang ingin Anda hash.

"MOD" ada di sana untuk mencegah meluap ke notasi ilmiah. 1009adalah yang utama, bisa menggunakan apa pun X sehingga X * 255 < max_int_size. 10 adalah arbitrer; gunakan apa saja. Nilai "Lain" adalah arbitrer (angka pi di sini!); gunakan apa saja. Lokasi karakter (1,3,5,7,9) sewenang-wenang; gunakan apa saja.

Pengecut Anonim
sumber
2
Jujur ini adalah jawaban yang paling sederhana, saya ragu tabrakan adalah masalah bagi sebagian besar kasus penggunaan excel.
gulungan
3

Untuk daftar yang cukup kecil, Anda dapat membuat pengacak (fungsi hash orang miskin) menggunakan fungsi Excel bawaan.

Misalnya

 =CODE(A2)*LEN(A2) + CODE(MID(A2,$A$1,$B$1))*LEN(MID(A2,$A$1,$B$1))

Di sini A1 dan B1 memegang huruf awal acak dan panjang string.

Sedikit mengutak-atik dan memeriksa dan dalam banyak kasus Anda bisa mendapatkan ID unik yang bisa diterapkan dengan cukup cepat.

Cara Kerja : Rumus menggunakan huruf pertama dari string dan huruf tetap yang diambil dari mid-string dan menggunakan LEN () sebagai 'fungsi mengipasi' untuk mengurangi kemungkinan tabrakan.

CAVEAT : ini bukan hash, tetapi ketika Anda perlu menyelesaikan sesuatu dengan cepat, dan dapat memeriksa hasilnya untuk melihat bahwa tidak ada tabrakan, itu bekerja dengan cukup baik.

Sunting: Jika string Anda harus memiliki panjang variabel (misalnya nama lengkap) tetapi ditarik dari catatan basis data dengan bidang lebar tetap, Anda ingin melakukannya seperti ini:

 =CODE(TRIM(C8))*LEN(TRIM(C8))
       +CODE(MID(TRIM(C8),$A$1,1))*LEN(MID(TRIM(C8),$A$1,$B$1))

sehingga panjangnya adalah pengacak yang berarti.

Assad Ebrahim
sumber
1
Jawaban bagus! (: "fungsi hash orang miskin", "peringatan", "cara kerjanya" :)
gila tentang rapi
1
Untuk "memeriksa hasil untuk melihat bahwa tidak ada tabrakan" Anda bisa mencoba / mengujinya dengan menjalankan DATA> REMOVE DUPLICATES dan lihat apakah ada. [jelas / mungkin, jika Anda membuat duplikat encouter, Anda bisa menjalankan kembali fungsi di atas untuk ini secara iteratif hingga tidak ada duplikat yang tersisa]
gila tentang natty
2

Saya menggunakan ini yang memberikan hasil yang cukup bagus dengan mencegah bentrok tanpa perlu menjalankan skrip setiap kali. Saya membutuhkan nilai antara 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)))

Ini mengambil surat dari seluruh string, mengambil nilai dari masing-masing surat, menambahkan nilai (untuk mencegah huruf yang sama di tempat yang berbeda memberikan hasil yang sama), mengalikan / membagi masing-masing dan menjalankan fungsi COS di atas total.

Cole Ant
sumber
1

Anda bisa mencoba ini. Jalankan Pseudo # pada dua kolom:

= + JIKA (DAN (ISBLANK (D3), ISBLANK (E3)), "", CODE (TRIM (D3 & E3)) * LEN (TRIM (D3 & E3)) + CODE (MID (TRIM (D3 & E3), $ A $ 1 * LEN) (D3 & E3), 1)) INT (LEN (TRIM (D3 & E3)) $ B $ 1))

Di mana A1 dan B1 menyimpan benih acak yang dimasukkan secara manual: 0

Michael Polubinski
sumber
0

Setahu saya tidak ada fungsi hash build ke Excel - Anda harus membangunnya sebagai Fungsi yang Ditentukan Pengguna di VBA.

Namun, harap dicatat bahwa untuk tujuan Anda, saya tidak berpikir menggunakan hash diperlukan atau benar-benar menguntungkan! VLOOKUPakan bekerja dengan baik pada 256 byte karena akan pada hash yang lebih kecil. Tentu, itu mungkin sedikit lebih lambat - sedikit yang pasti sangat kecil sehingga tak terukur. Dan kemudian menambahkan nilai hash lebih banyak usaha untuk Anda - dan untuk Excel ...

Peter Albert
sumber
ya ... Saya tahu itu, tetapi hanya dari sudut pandang presentasi, saya lebih suka menampilkan, katakanlah, 15 byte hash yang 256 byte titledi panel kiri beku saya ...
dwwilson66