Bir karma değeri oluşturmak için bir Excel işlevi var mı?


26

Belge adına göre anahtarlanmış çok sayıda veri listesiyle çalışıyorum. Belge isimleri, çok açıklayıcı olsa da, onları incelemem gerekiyorsa (256 byte'a kadar bir çok emlak var) ve ihtiyaç duyduğumda kolayca yeniden üretilebilen daha küçük bir anahtar alanı oluşturmayı çok isterim. bir yapmak için VLOOKUPbaşka workseet veya çalışma kitabından.

Her başlık için benzersiz ve tekrarlanabilir bir başlıktan bir karmaşanın en uygun olacağını düşünüyorum. Kullanılabilir bir işlev var mı veya kendi algoritmamı mı geliştiriyorum?

Bu veya başka bir strateji hakkında herhangi bir düşünce veya fikir?

Yanıtlar:


34

Kendi işlevini yazmana gerek yok - diğerleri zaten bunu senin için yaptı.
Örneğin, bu stackoverflow cevabında beş VBA hash işlevi topladım ve karşılaştırdım.

Şahsen ben bu VBA işlevini kullanıyorum

  • =BASE64SHA1(A1)Makroyu bir VBA modülüne kopyaladıktan sonra Excel'de çağrılır.
  • "Microsoft MSXML" kütüphanesini kullandığı için .NET'i gerektirir (geç bağlamayla)

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

Karma uzunluğu özelleştirme

  • karma başlangıçta 28 karakter uzunluğunda unicode bir dizedir (büyük / küçük harfe duyarlı + özel karakterler)
  • Karma uzunluğu bu satırla özelleştirin: Const cutoff As Integer = 5
  • 4 basamaklı hash = 6895 çizgide 36 çarpışma =% 0.5 çarpışma oranı
  • 5 basamak hash = 6895 satırda 0 çarpışma =% 0 çarpışma oranı

Ayrıca, .NET gerektirmeyen ve harici kitaplıklar kullanmayan karma işlevler de vardır ( üç CRC16 işlevinin tümü ). Ancak karma daha uzun ve daha fazla çarpışma üretir.

Ayrıca bu örnek çalışma kitabını indirebilir ve 5 karma uygulamanın tümü ile oynayabilirsiniz. Gördüğünüz gibi ilk sayfada iyi bir karşılaştırma var.


1
Harika görünüyor. Ancak Excel'in geri dönmesini engellemek için yeterli VBA deneyimim yok #NAME?. Kodu görüntüle> kodu kesip yeni pencereye yapıştırın - gezginde doğru çalışma sayfasında> makro etkin çalışma sayfası olarak kaydet> kapat ve seçime dön ... başka bir şey eksik? Bir şekilde derlememe gerek var mı?
dwwilson66

Evet ... açıklığa kavuşturmak için ... çalışma sayfası sekmesine gittiğimde açılan yeni kod penceresine yapıştırdım> kodu görüntüle ... Şu anda örneği indiriyorum, ancak excel'in kodumu neden tanımadığını anlamak istiyorum
dwwilson66

WooHoo ... örnek kağıdı yardımcı oldu. Yaptığım kod bir MODULE penceresine değil OBJECT penceresine yapıştırdım. Şimdi çalışma kitabımda karmaşa alıyorum!
dwwilson66

1
Bu mükemmel bir araçtır.
Jay Killeen

1
cutoffParametreli ve isteğe bağlı olarak farklı bir varsayılan değer ile İşlev parametre listesine taşıyabilir Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) ve işlev içindeki bildirimi kaldırabilirsiniz.
Çekirdek

9

Çarpışmalar hakkında çok fazla umrumda değil, ancak değişken uzunluklu bir dize alanına dayanan zayıf bir sözde ve sıralayıcıya ihtiyacım vardı. İşte iyi çalışan çılgın bir çözüm:

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

Karmak Z2istediğiniz dizeyi içeren hücre nerede .

Bilimsel gösterimde taşmaları önlemek için "MOD" ler vardır. 1009asal, X * 255 <olacak şekilde X'i kullanabilir max_int_size. 10 keyfidir; bir şey kullan. "Başka" değerler isteğe bağlıdır (burada pi rakamları!); bir şey kullan. Karakterlerin yeri (1,3,5,7,9) keyfidir; bir şey kullan.


2
Dürüst olmak gerekirse, bu en basit cevap, çarpışmaların çoğu excel kullanım durumları için bir sorun olduğunu sanmıyorum.
rulo

3

Oldukça küçük bir liste için, yerleşik Excel işlevlerini kullanarak bir karıştırıcı (yoksul erkeğin karma işlevi) oluşturabilirsiniz.

Örneğin

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

Burada A1 ve B1 rastgele bir başlangıç ​​harfini ve string uzunluğunu tutar.

Biraz korkutucu ve kontrol ve çoğu durumda oldukça hızlı bir şekilde uygulanabilir bir benzersiz kimlik alabilirsiniz.

Nasıl Çalışır : Formül, dizenin ilk harfini ve orta dizeden alınan sabit bir harfi kullanır ve çarpışma olasılığını azaltmak için LEN () işlevini 'fan işlevi' olarak kullanır.

CAVEAT : bu bir karmaşa değildir , ancak hızlı bir şekilde bir şeyler yapmanız gerektiğinde ve çarpışma olmadığını görmek için sonuçları inceleyebilir, oldukça iyi çalışır.

Düzenleme: Dizeleriniz değişken uzunluklara sahipse (örneğin tam adlar), ancak sabit genişlikte alanları olan bir veritabanı kaydından çıkarılmışsa, bunu yapmak istersiniz:

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

böylece uzunluklar anlamlı bir karıştırıcıdır.


1
Mükemmel cevap! (: "zavallı adamın hash işlevi", "ihmal", "nasıl çalıştığı" :)
natty

1
To "hiçbir çarpışmalar olduğunu görmek sonuçlarını incelemek" basitçe deneyebilirsiniz / test bu VERİ> KALDIR yinelemeleri çalıştırarak ve herhangi olup olmadığını görmek. [Eğer encouter çiftleri yaparsanız hiçbir çiftleri kalmayıncaya kadar belli ki / tahminen, sadece bu iteratif için yukarıdaki işlevini yeniden çalıştırılırsa olabilir]
Nutty işe yatkın hakkında

2

Her seferinde bir komut dosyası çalıştırmaya gerek kalmadan çatışmayı önleme konusunda oldukça iyi sonuçlar veren bunu kullanıyorum. 0 - 1 arasında bir değere ihtiyacım vardı.

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

Dizenin karşısındaki harfleri seçer, bu harflerin her birinin değerini alır, değer ekler (aynı sonuçları veren farklı yerlerde aynı harfleri önlemek için), her birini çarpar / böler ve toplamın üzerinde bir COS işlevi çalıştırır.


1

Bunu deneyebilirsin. İki sütunda bir Sözde # çalıştırın:

= + EĞER (VE (ISBLANK (D3), ISBLANK (E3)), "", KOD (TRIM (D3 & E3)) * LEN (TRIM (D3 & E3)) + KOD (MID (TRIM (D3 & E3), $ A $ 1 * LEN (D3 ve E3), 1)) INT (LEN (TRIM (D3 ve E3))) B $ 1))

A1 ve B1 depolarının rastgele tohumları manuel olarak girdiği yerde: 0


0

Bildiğim kadarıyla Excel'de yerleşik bir işlev yoktur - VBA'da bir Kullanıcı Tanımlı İşlev olarak bir yapı kurmanız gerekir.

Ancak, amacınız için bir karma kullanımın gerekli veya gerçekten avantajlı olduğunu düşünmüyorum! VLOOKUP256 byte üzerinde daha küçük bir karmada olduğu gibi çalışacaktır. Elbette, ölçülemeyecek kadar küçük olduğundan kesin olarak biraz daha yavaş olabilir. Ve sonra karma değerleri eklemek sizin için daha fazla çaba gerektirir - ve Excel için ...


evet ... bunu biliyorum, ama sadece sunum açısından, titledonmuş sol
bölmemde
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.