Чи існує функція Excel для створення хеш-значення?


26

Я працюю з низкою списків даних, які вводяться назви документа. Назви документів, хоч і є дуже описовими, досить громіздкі, якщо мені потрібно переглянути їх (до 256 байт - це велика кількість нерухомості), і я хотів би створити менше ключове поле, яке легко відтворюється, якщо мені це потрібно робити VLOOKUPз іншого робочого листа чи робочої книги.

Я думаю, що хеш із заголовка, який був би унікальним і відтворюваним для кожного заголовка, був би найбільш відповідним. Чи є функція, чи я розглядаю розробку власного алгоритму?

Якісь думки чи ідеї щодо тієї чи іншої стратегії?

Відповіді:


34

Вам не потрібно писати власну функцію - інші це вже зробили за вас.
Наприклад, я зібрав і порівняв п'ять хеш-функцій VBA на цю відповідь stackoverflow

Особисто я використовую цю функцію VBA

  • його викликає =BASE64SHA1(A1)в Excel після того, як ви скопіювали макрос у модуль VBA
  • вимагає .NET, оскільки він використовує бібліотеку "Microsoft MSXML" (з пізнім прив'язкою)

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

Налаштування довжини хешу

  • спочатку хеш - це 28 символів рядка Unicode (з урахуванням регістру + спеціальні символи)
  • Ви налаштовуєте довжину хеша за допомогою цього рядка: Const cutoff As Integer = 5
  • 4 цифри хеша = 36 зіткнень у 6895 рядках = 0,5% швидкості зіткнення
  • 5 цифр хеш = 0 зіткнень у 6895 рядках = 0% швидкості зіткнення

Є також хеш-функції ( всі три функції CRC16 ), які не потребують .NET і не використовують зовнішні бібліотеки. Але хеш довший і створює більше зіткнень.

Ви також можете просто завантажити цю прикладну робочу книгу і пограти з усіма 5 хеш-реалізаціями. Як бачите, на першому аркуші є хороше порівняння


1
Виглядає здорово. Однак у мене недостатньо досвіду VBA, щоб запобігти поверненню Excel #NAME?. Перегляд коду> вирізати та вставити код у нове вікно - на правильному робочому аркуші в навігаторі> зберегти як робочий аркуш із підтримкою макросу> закрити та повернутись до excel ... що ще мені не вистачає? Чи потрібно мені якось це складати?
dwwilson66

Так ... для уточнення ... я вставив його у нове вікно коду, яке спливе, коли я перейшов на вкладку робочого листа> Переглянути код ... Завантажую зразок зараз, але я хотів би зрозуміти, чому excel не визнає мій код
dwwilson66

WooHoo ... зразок аркуша допоміг. Зрозумів, я вставив код у вікно ОБ'ЄКТУ та перевершив його, а не МОДУЛЬНЕ вікно. Я зараз отримую хеши у своїй робочій книжці!
dwwilson66

1
Це відмінний інструмент.
Джей Кілін

1
Ви можете зробити cutoffпараметризований та необов’язковий з іншим типовим типом, перемістивши його до списку параметрів функції Public Function BASE64SHA1(ByVal sTextToHash As String, Optional ByVal cutoff As Integer = 8) та видаливши декларацію всередині функції.
Коренева

9

Мене не дуже хвилює зіткнення, але мені знадобився слабкий псевдорандомизатор рядків, заснований на полі рядка змінної довжини. Ось одне божевільне рішення, яке добре спрацювало:

=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, щоб X * 255 < max_int_size. 10 - довільне; використовувати що завгодно. Значення "Else" довільні (цифри pi тут!); використовувати що завгодно. Розташування символів (1,3,5,7,9) довільне; використовувати що завгодно.


2
Чесно кажучи, це найпростіша відповідь, я сумніваюся, зіткнення є проблемою для більшості випадків використання excel.
котиться

3

Для досить невеликого списку ви можете створити скремблер (хеш-функція поганого чоловіка) за допомогою вбудованих функцій Excel.

Напр

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

Тут A1 і B1 містять випадкову початкову літеру та довжину рядка.

Трохи підгортаючи та перевіряючи, і в більшості випадків ви можете швидко отримати діючий унікальний ідентифікатор.

Як це працює : Формула використовує першу літеру рядка та фіксовану літеру, взяті з середнього рядка, і використовує LEN () як "функцію розпушування", щоб зменшити ймовірність зіткнень.

CAVEAT : це не хеш, але коли вам потрібно щось швидко зробити, і ви можете перевірити результати, щоб побачити, що немає зіткнень, це працює досить добре.

Редагувати: Якщо ваші рядки повинні мати змінну довжину (наприклад, повні імена), але витягнуті з запису бази даних із полями фіксованої ширини, вам потрібно зробити це так:

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

щоб довжини були змістовними скремблерами.


1
Чудова відповідь! (: "хеш-функція бідолахи", "застереження", "як це працює" :)
горіх про natty

1
Щоб "перевірити результати, щоб побачити, що немає зіткнень", ви можете просто спробувати / протестувати це, запустивши DATA> REMOVE DUPLICATES і побачити, чи є такі. [очевидно / імовірно, якщо ви сприяєте повторюванню дублікатів, ви можете просто запустити вищевказану функцію для цих ітеративних дій, поки не залишиться жодних дублікатів]
nutty про natty

2

Я використовую це, що дає досить хороші результати із запобіганням зіткнення, без необхідності щоразу запускати сценарій. Мені потрібно було значення між 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 над загальним.


1

Ви можете спробувати це. Запустіть псевдо # у двох стовпцях:

= + АБО (І (ISBLANK (D3), ISBLANK (E3)), "", КОД (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))

Там, де А1 і В1 зберігають випадкові насіння, введені вручну: 0


0

Наскільки мені відомо, в Excel немає вбудованої хеш-функції - вам потрібно буде побудувати її як визначену користувачем функцію в VBA.

Однак зауважте, що для ваших цілей я не думаю, що використовувати хеш не потрібно чи справді вигідно! VLOOKUPбуде працювати так само добре на 256 байтах, як і на меншому хеші. Звичайно, це може бути крихітний трохи повільніше - біт, напевно, такий малий, що він незмірний. А потім додавання хеш-значень більше зусиль для вас - і для Excel ...


так ... Я це знаю, але тільки з точки зору презентації я б краще відобразив, скажімо, 15 байт хешу, що 256 байт titleу моїй лівій панелі замороженого ...
dwwilson66
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.