Подтвердить что ты не робот

Постоянное хеширование строк в Python

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

4b9b3361

Ответ 1

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

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'

Ответ 2

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

>>> import hashlib
>>> int(hashlib.md5('Hello, world!').hexdigest(), 16)
144653930895353261282233826065192032313L

Ответ 3

Вот моя реализация 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)

Ответ 4

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

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

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 также предоставляет несколько других хеш-функций.

Ответ 5

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

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

aString = "don't panic"
reduce( lambda x,y:x+y, map( lambda x:ord(x[0])*x[1],zip( aString, range( 1, len( aString ) ) ) ) )