Есть ли функция Excel для создания хеш-значения?


26

Я работаю с несколькими списками данных, которые вводятся по имени документа. Имена документов, хотя и очень наглядны, довольно громоздки, если мне нужно просматривать их (до 256 байт - это много места), и я хотел бы иметь возможность создать меньшее ключевое поле, которое легко воспроизводится в случае необходимости сделать VLOOKUPиз другого рабочего листа или рабочей книги.

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

Есть мысли или идеи по поводу этой или другой стратегии?

Ответы:


34

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

Лично я использую эту функцию 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

Настройка длины хеша

  • изначально хеш - это строка в Unicode длиной 28 символов (с учетом регистра + специальные символы)
  • Вы настраиваете длину хеша с помощью этой строки: 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 ... образец листа помог. Понял, что я вставил код в окно OBJECT и превзошел его, а не в окно MODULE. Теперь я получаю хэши в своей книге!
dwwilson66

1
Это отличный инструмент.
Джей Киллин

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

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 произвольно; использовать что угодно. «Остальные» значения являются произвольными (цифры пи здесь!); использовать что угодно. Расположение символов (1,3,5,7,9) произвольно; использовать что угодно.


2
Честно говоря, это самый простой ответ, я сомневаюсь, что коллизии являются проблемой для большинства прецедентов.
Выпускается

3

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

Например

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

Здесь A1 и B1 содержат случайную начальную букву и длину строки.

Немного возиться и проверять, и в большинстве случаев вы можете получить работоспособный уникальный идентификатор довольно быстро.

Как это работает : формула использует первую букву строки и фиксированную букву, взятую из средней строки, и использует LEN () в качестве «функции раздувания», чтобы уменьшить вероятность столкновений.

ПРЕДУПРЕЖДЕНИЕ : это не хеш, но когда вам нужно что-то сделать быстро и проверить результаты, чтобы убедиться, что нет столкновений, это работает довольно хорошо.

Редактировать: если ваши строки должны иметь переменную длину (например, полные имена), но извлекаются из записи базы данных с полями фиксированной ширины, вы захотите сделать это так:

 =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 и посмотреть, есть ли они. [очевидно / предположительно, если вы делаете дубликаты-получатели, вы можете просто повторно запустить вышеупомянутую функцию для них итеративно, пока не останется никаких дубликатов]
чокнутый из-за 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

Вы можете попробовать это. Запустите псевдо # на двух столбцах:

= + ЕСЛИ (И (ЕПУСТО (D3), ЕПУСТО (Е3)), "", КОД (TRIM (D3 & Е3)) * LEN (TRIM (D3 & Е3)) + код (MID (TRIM (D3 & Е3), $ A $ 1 * LEN (D3 и E3), 1)) INT (LEN (TRIM (D3 и E3)) $ B $ 1))

Где A1 и B1 хранят случайные семена, введенные вручную: 0


0

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

Тем не менее, обратите внимание, что для вашей цели я не думаю, что использование хэша является обязательным или действительно выгодным! VLOOKUPбудет работать с 256 байтами так же хорошо, как с меньшим хешем. Конечно, это может быть чуть-чуть медленнее, точно настолько маленьким, что это неизмеримо. А затем добавление значений хеш-функции требует больше усилий - и для Excel ...


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