Постоянное хеширование строк в Python - PullRequest
22 голосов
/ 24 марта 2010

Как бы вы преобразовали произвольную строку в уникальное целое число, которое было бы одинаковым для сеансов и платформ Python? Например, hash('my string') не будет работать, потому что для каждой сессии Python и платформы возвращается различное значение.

Ответы [ 5 ]

31 голосов
/ 24 марта 2010

Используйте алгоритм хеширования, такой как MD5 или SHA1, затем преобразуйте hexdigest через int():

>>> import hashlib
>>> int(hashlib.md5('Hello, world!').hexdigest(), 16)
144653930895353261282233826065192032313L
8 голосов
/ 24 марта 2010

Если хеш-функция действительно не работает для вас, вы можете превратить строку в число.

my_string = 'my string'
def string_to_int(s):
    ord3 = lambda x : '%.3d' % ord(x)
    return int(''.join(map(ord3, s)))

In[10]: string_to_int(my_string)
Out[11]: 109121032115116114105110103L

Это обратимо, сопоставляя каждый триплет через chr.

def int_to_string(n)
    s = str(n)
    return ''.join([chr(int(s[i:i+3])) for i in range(0, len(s), 3)])

In[12]: int_to_string(109121032115116114105110103L)
Out[13]: 'my string'
3 голосов
/ 23 октября 2012

Вот моя реализация python27 для алгоритмов, перечисленных здесь: http://www.cse.yorku.ca/~oz/hash.html. Понятия не имею, эффективны они или нет.

from ctypes import c_ulong

def ulong(i): return c_ulong(i).value  # numpy would be better if available

def djb2(L):
  """
  h = 5381
  for c in L:
    h = ((h << 5) + h) + ord(c) # h * 33 + c
  return h
  """
  return reduce(lambda h,c: ord(c) + ((h << 5) + h), L, 5381)

def djb2_l(L):
  return reduce(lambda h,c: ulong(ord(c) + ((h << 5) + h)), L, 5381)

def sdbm(L):
  """
  h = 0
  for c in L:
    h = ord(c) + (h << 6) + (h << 16) - h
  return h
  """
  return reduce(lambda h,c: ord(c) + (h << 6) + (h << 16) - h, L, 0)

def sdbm_l(L):
  return reduce(lambda h,c: ulong(ord(c) + (h << 6) + (h << 16) - h), L, 0)

def loselose(L):
  """
  h = 0
  for c in L:
    h += ord(c);
    return h
  """
  return sum(ord(c) for c in L)

def loselose_l(L):
  return reduce(lambda h,c: ulong(ord(c) + h), L, 0)
2 голосов
/ 24 марта 2010

Во-первых, вы, вероятно, на самом деле не хотите, чтобы целые числа были фактически уникальными. Если вы это сделаете, то ваши номера могут быть неограниченными по размеру. Если это действительно то, что вам нужно, вы можете использовать библиотеку bignum и интерпретировать биты строки как представление (потенциально очень большого) целого числа. Если ваши строки могут содержать символ \ 0, тогда вам следует добавить 1, чтобы вы могли различить, например, "\ 0 \ 0" из "\ 0".

Теперь, если вы предпочитаете числа ограниченного размера, вы будете использовать некоторую форму хеширования. MD5 будет работать, но это излишне для заявленной цели. Я рекомендую вместо этого использовать sdbm, он работает очень хорошо. В Си это выглядит так:

static unsigned long sdbm(unsigned char *str)
{
    unsigned long hash = 0;
    int c;

    while (c = *str++)
        hash = c + (hash << 6) + (hash << 16) - hash;

    return hash;
}

Источник, http://www.cse.yorku.ca/~oz/hash.html, также представляет несколько других хеш-функций.

0 голосов
/ 23 января 2013

Вот еще один вариант, довольно грубый (вероятно, со множеством столкновений) и не очень четкий.

Он работал для генерации целого (а затем и случайного цвета) для разных строк:

aString = "don't panic"
reduce( lambda x,y:x+y, map( lambda x:ord(x[0])*x[1],zip( aString, range( 1, len( aString ) ) ) ) )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...