¿Cómo dividir una cadena en 8 dígitos?

106

¿Hay alguna forma de que pueda convertir una cadena aleatoria en un número de 8 dígitos sin implementar ningún algoritmo yo mismo?

Dorafmon
fuente
2
hash ("su cadena")% 100000000
Theran
2
8 dígitos parecen pequeños y pueden resultar en colisiones de hashes si tiene una gran cantidad de registros. stackoverflow.com/questions/1303021/…
DhruvPathak
¡Usa hashlib ya que el hash tiene otro propósito!
arquitectónico
2
Cualquier número finito de dígitos resultará en colisiones para un número suficientemente grande de elementos hash, por eso no debe tratarlos como claves únicas; tiende a convertirse en el problema del cumpleaños.
Alex North-Keys
1
Elegí "CityHash" para codificar cadenas de números enteros de 19 dígitos (enteros de 64 bits), con la esperanza de que esto conduzca a menos colisiones potenciales que la sugerencia de Raymond a continuación. en.wikipedia.org/wiki/List_of_hash_functions
tryptofame

Respuestas:

154

Sí, puede utilizar los módulos hashlib incorporados o la función hash incorporada. Luego, corte los últimos ocho dígitos usando operaciones de módulo o operaciones de corte de cadenas en la forma entera del hash:

>>> s = 'she sells sea shells by the sea shore'

>>> # Use hashlib
>>> import hashlib
>>> int(hashlib.sha1(s).hexdigest(), 16) % (10 ** 8)
58097614L

>>> # Use hash()
>>> abs(hash(s)) % (10 ** 8)
82148974
Raymond Hettinger
fuente
26
anuncio de servicio público ... esta técnica en realidad no da como resultado un valor hash único para la cadena; calcula un hash y luego se convierte en un valor único no garantizado
twneale
88
anuncio de servicio público ... excepto en el caso especial de hashes perfectos sobre un conjunto limitado de valores de entrada, no se supone que las funciones hash generen valores únicos garantizados.
Raymond Hettinger
5
¿Leíste la pregunta del OP? Él (o ella) quería (o necesitaba) 8 lugares decimales. Además, la forma en que funcionan las tablas hash es en un pequeño espacio de búsqueda (la tabla dispersa). Parece que no sabe que las funciones de hash de búsqueda se usan comúnmente y que no le importa la pregunta real que se hizo.
Raymond Hettinger
17
Leí la pregunta. Simplemente estoy observando que en el mismo espacio de entrada que SHA-1, su respuesta es astronómicamente más probable que produzca una colisión que no. La pregunta requiere implícitamente al menos cierto grado de unicidad, pero su respuesta es una función hash con el mismo espíritu que una que simplemente devuelve 12345678 para cada entrada. Pude generar experimentalmente una colisión con tan solo 1000 entradas usando este método. Para conservar la misma probabilidad de colisión que SHA-1, tendría que asignar SHA-1 no truncados a números enteros de 8 dígitos. Creo que es digno de un
anuncio de servicio público
20
Cuidado, no se garantiza que los hash (s) den los mismos resultados en todas las plataformas y ejecuciones.
Sr. Napik
94

La respuesta de Raymond es excelente para python2 (sin embargo, no necesita el abs () ni el parens alrededor de 10 ** 8). Sin embargo, para python3, existen importantes advertencias. Primero, deberá asegurarse de pasar una cadena codificada. En estos días, en la mayoría de las circunstancias, probablemente también sea mejor evitar sha-1 y usar algo como sha-256 en su lugar. Entonces, el enfoque de hashlib sería:

>>> import hashlib
>>> s = 'your string'
>>> int(hashlib.sha256(s.encode('utf-8')).hexdigest(), 16) % 10**8
80262417

Si desea utilizar la función hash () en su lugar, la advertencia importante es que, a diferencia de Python 2.x, en Python 3.x, el resultado de hash () solo será coherente dentro de un proceso, no entre las invocaciones de Python. Mira aquí:

$ python -V
Python 2.7.5
$ python -c 'print(hash("foo"))'
-4177197833195190597
$ python -c 'print(hash("foo"))'
-4177197833195190597

$ python3 -V
Python 3.4.2
$ python3 -c 'print(hash("foo"))'
5790391865899772265
$ python3 -c 'print(hash("foo"))'
-8152690834165248934

Esto significa la solución basada en hash () sugerida, que se puede acortar a solo:

hash(s) % 10**8

solo devolverá el mismo valor dentro de una ejecución de script determinada:

#Python 2:
$ python2 -c 's="your string"; print(hash(s) % 10**8)'
52304543
$ python2 -c 's="your string"; print(hash(s) % 10**8)'
52304543

#Python 3:
$ python3 -c 's="your string"; print(hash(s) % 10**8)'
12954124
$ python3 -c 's="your string"; print(hash(s) % 10**8)'
32065451

Entonces, dependiendo de si esto es importante en su aplicación (lo hizo en la mía), probablemente querrá ceñirse al enfoque basado en hashlib.

JJC
fuente
2
Cabe señalar que esta respuesta tiene una advertencia muy importante desde Python 3.3, para protegerse contra Python 3.3 y versiones posteriores, use una semilla hash aleatoria al inicio.
Wolph
Si los dígitos no son su requisito principal, también puede usar la hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]bruja todavía tendrá colisiones
lony
¡Deberían poner eso en la caja!
Tomasz
3

Solo para completar la respuesta de JJC, en Python 3.5.3 el comportamiento es correcto si usa hashlib de esta manera:

$ python3 -c '
import hashlib
hash_object = hashlib.sha256(b"Caroline")
hex_dig = hash_object.hexdigest()
print(hex_dig)
'
739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded
$ python3 -c '
import hashlib
hash_object = hashlib.sha256(b"Caroline")
hex_dig = hash_object.hexdigest()
print(hex_dig)
'
739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded

$ python3 -V
Python 3.5.3
usuario8948052
fuente
-3

Estoy compartiendo nuestra implementación de nodejs de la solución implementada por @Raymond Hettinger.

var crypto = require('crypto');
var s = 'she sells sea shells by the sea shore';
console.log(BigInt('0x' + crypto.createHash('sha1').update(s).digest('hex'))%(10n ** 8n));
usuario 923227
fuente
¿Estás compartiendo una solución de nodejs en una pregunta sobre Python?
Harabeck
Sí, cuando estábamos construyendo el sistema, el backend procesó esto usando python mientras que el frontend usó node.js. Necesario para asegurarse de que ambos funcionen a la perfección.
usuario 923227