web-dev-qa-db-fra.com

Chaîne vers un hachage entier unique

J'essaie de développer un système capable de transformer ma chaîne en une valeur intégrale unique, ce qui signifie par exemple que le mot "compte" a une valeur numérique chiffrée de 0891 et qu'aucun autre mot ne peut être converti en 0891 avec le même processus de conversion. not doit cependant pouvoir être reconverti en entier sous forme de chaîne.

En même temps, il dépendra des règles de structure Word, ce qui signifie que des mots tels que "précision" et "annonce" auront un nombre généré supérieur à 0891 et que des mots tels que "un", "boulier" et "abréviation" auront un nombre généré inférieur à 0891.

Le but de cette application est de servir similaire à un index ou une clé primaire. La raison pour laquelle je n'utilise pas d'index d'incrémentation est pour des raisons de sécurité et tient à la dépendance des index par rapport au nombre de données de l'ensemble.

(par exemple.)

[0] A, [1] B, [2] C, [3] D, [4] E, [5] F

Les lettres ci-dessus ont chacune un index correspondant, E un index de 4

Cependant, si les données sont soudainement augmentées ou diminuées, elles sont triées.

[0] A, [1] AA, [2] AAB, [3] C, [4] D, [5] DA, [6] DZ, [7] E, [8] F

E a maintenant l'indice de 7

Chaque mot doit avoir un équivalent intégral indépendant unique et avoir les poids correspondants.

J'ai besoin de savoir s'il existe un algorithme capable de faire ce qui précède.

Toute aide serait appréciée.

17
Treize

Cela n’est pas possible avec les contraintes que vous avez indiquées, à moins d’imposer une longueur maximale.

Supposons que k("a") et k("b") sont les codes de ces deux chaînes.

Avec vos contraintes, vous recherchez un nombre entier unique se situant entre ces deux valeurs, mais k("a") < k("a....a") < k("b"). Comme il existe un nombre infini de chaînes de style "a....a" (et "akjhdsfkjhs") qui doivent s'inscrire entre les deux codes, un tel code - préservant l'ordre general, ne peut exister de code de longueur fixe unique pour des chaînes de longueur arbitraire. Parce que vous auriez besoin d'autant d'entiers que de chaînes, et comme les chaînes ne sont pas limitées par la longueur, cela ne peut pas fonctionner.

Supprimez des propriétés générales (ne pas autoriser l'insertion de nouvelles chaînes), uniques (autorisez les collisions - utilisez par exemple les quatre premières lettres comme code!), La longueur non limitée (jusqu'à 3 caractères, par exemple) ou la propriété préservant l'ordre.

10
Erich Schubert

Par souci de simplicité, je suppose que a à z sont les seuls caractères autorisés dans les mots.

Attribuons des nombres jusqu'à la longueur de 2 chaînes:

String Value
a      0
aa     1
ab     2
...
az     26
b      27
ba     28
bb     29
...
bz     53
c      54
...

Maintenant, en regardant simplement cela, vous devriez pouvoir comprendre que, pour déterminer le décalage d'une chaîne donnée de longueur plus courte, vous aurez besoin de la longueur maximale autorisée. Supposons que nous connaissons ce nombre.

Pour la simplicité algorithmique, nous préférerions commencer à 27: (n'hésitez pas à essayer de le comprendre pour à partir de 0, vous aurez besoin de cas particuliers)

String Value
a      27
aa     28
ab     29
...

Donc, essentiellement, le caractère le plus à gauche contribue à une valeur 27*(1-26) (pour a-z) et le caractère suivant à droite, s'il en existe une, contribue 1-26 (pour a-z) à la valeur d'une chaîne.

Cela peut maintenant être généralisé pour dire que le nombre le plus à gauche contribuerait à (1-26)*27^(len-1), au prochain (1-26)*27^(len-2), et ainsi de suite, jusqu'au (1-26)*27^0.

Ce qui m'amène à du code Java:

long result = 0;
for (int i = 0; i < s.length(); i++)
   result += pow(27, MAX_LENGTH - i - 1)*(1 + s.charAt(i) - 'a');

Test de sortie:

a                    =   150094635296999121
aa                   =   155653695863554644
aaa                  =   155859586995649293
aaaa                 =   155867212593134280
aaaaa                =   155867495022670761
abacus               =   161447654121636735
abbreviation         =   161763445236432690
account              =   167509959568845165
accuracy             =   167554723653128367
announcement         =   230924421746611173
z                    =  3902460517721977146

Démo en ligne .

Oui, ce sont des nombres assez gros pour une longueur allant jusqu'à 13 chaînes, mais, sans attribuer séquentiellement des nombres à des mots dans un dictionnaire, vous ne pouvez pas faire mieux (sauf que vous pouvez commencer à 0, ce qui est relativement parlant , une petite différence), car il existe autant de possibilités de séquences de lettres.

8
Dukeling

Pour l’unicité, commencez par attribuer des nombres premiers aux lettres: A -> 2, B -> 3, C -> 5, D -> 7 etc.

Pour calculer la "clé" d'une lettre donnée dans un mot, élevez le nombre premier à la puissance de l'index de position dans le mot. Pour obtenir la "clé" de tout le mot, multipliez toutes les clés de lettres ensemble.

Par exemple, le mot CAB:

C -> 5 ^ 1 = 5
A -> 2 ^ 2 = 4
B -> 3 ^ 3 = 81
CAB -> 5 * 4 * 81 =  1620.

Aucune autre Parole ne vous donnera jamais 1620 comme clé. 

Remarque: vous n'avez pas besoin de commencer par A -> 2 ni d'affecter des nombres premiers aux caractères de l'alphabet dans l'ordre, tant que vous suivez le mappage. N'oubliez pas non plus que les résultats seront très rapidement grands.

Cependant, gardez à l'esprit les autres commentaires sur la sécurité - il ne s'agit pas d'un algorithme particulièrement sécurisé. 

3
Vicky

Si vous n'avez aucune limite sur le nombre d'octets que ces entiers peuvent occuper, les codes d'octet sous-jacents (par exemple, Ascii) pour chaque caractère vous donneront une représentation entière. De manière équivalente, affectez 0 = A, 1 = B jusqu'à Z = 25, puis le mot lui-même est l'entier de la base 26.

2
Stochastically

Tu peux le faire:

SEPARETOR = '000'
string_to_hash = "some_string"
hashed_result = int(SEPARETOR.join(list(str(ord(character)) for character in string_to_hash)))

Prendre plaisir!

1
Yuval Pruss

Attribuez une valeur première unique à chaque alphabet par ordre croissant (ordre non nécessaire).

Remarque: comme la multiplication de nombres premiers est un résultat unique qui ne peut être multiplié que par ces nombres, il vous donnera des valeurs uniques pour chaque mot.

Algorithme: 

int hash = 0;
forEach (int i = 0 ; i < Word.length ; i++)
{ 
   hash *= (prime[c[i]] ** (length - i)); 
}

prime - Un tableau pour stocker les valeurs principales correspondant à chacune

powered to (length - 1) pour donner une valeur à l'endroit où ce caractère apparaît pour conserver l'ordre du dictionnaire.

Cet algorithme donnera des valeurs suffisamment grandes pour que envahisse votre tableau. 

De plus: mots de plus petites longueurs peuvent donner des valeurs plus basses que certains mots de plus grande longueur et cela peut affecter l'ordre du dictionnaire mais je ne suis pas sûr de savoir pourquoi vous voulez un ordre de dictionnaire car l'unicité sera maintenue ici. 

1
Rahul

Oui, mais surtout non.

Oui, comme dans la réponse stochastique. En configurant une base 26 (ou une base 128 pour tout le code ASCII), vous pouvez théoriquement hacher chaque chaîne de manière unique.

D'un autre côté, ce n'est pas pratique, non seulement les nombres deviendraient trop gros pour la plupart des langues, mais ce serait aussi un processus extrêmement fastidieux. De plus, si les chaînes sont autorisées à être infinies, une forme de l'argument diagonal de Cantor peut également être appliquée pour "casser" cet algorithme. Il est impossible de créer un mappage un à un d'un ensemble avec la cardinalité aleph-one (chaînes) avec un ensemble de cardinalité aleph-null (ints).

0
tox123