2009-06-30 8 views
2

Je crée une base de données orientée fichier de certains résultats de test effectués par divers utilisateurs. Pour cela, j'ai besoin de générer un identifiant unique pour chaque entrée dans la base de données. Les ids doivent satisfaire aux exigences suivantes:Comment créer des identifiants uniques en Perl?

  • Ids devrait être assez petit (6 caractères maximum)
  • Pour tous les cas de test et la combinaison de l'utilisateur à chaque fois même id doit être généré

Ce que j'ai essayé était une simple fonction de hachage BKDR avec une valeur de 31 graines et utilisé la fonction ord() comme suit:

@chars = split(//,$hash_var); 

$hash = 0; 
$seed = 31; 

foreach $char (@chars) { 
    if($char !~ m/\d/) { 
     $hash = ($seed * $hash) + ord($char); 
    } 
    else { 
     $hash = ($seed * $hash) + $char ; 
    } 
} 

$hash = ($hash & 0x7FFFFFFF) % 1000; 
$hash = "$chars[0]$chars[$#chars]$hash" ; 

Cela conduit parfois à des résultats même pour diverses combinaisons u ie la nicotité n'est pas observée. Est-ce leur tout autre moyen d'accomplir cela? La modification de la valeur des graines aide-t-elle à réaliser l'unicité.

Répondre

3

Une partie de votre problème est peut-être que vous utilisez des maths en virgule flottante et BKDR veut presque certainement des maths entiers. Vous pouvez corriger ce bogue en disant

my @chars = split(//,$hash_var); 

my $hash = 0; 
my $seed = 31; 

for my $char (@chars) { 
    use integer; 
    if($char !~ m/\d/) { 
     $hash = ($seed * $hash) + ord($char); 
    } 
    else { 
     $hash = ($seed * $hash) + $char ; 
    } 
} 

$hash = ($hash & 0x7FFFFFFF) % 1000; 
$hash = "$chars[0]$chars[$#chars]$hash" ; 

Un autre réglage qui pourrait vous aider est l'utilisation de caractères autres que le premier et le dernier. Si le premier et le dernier caractère ont tendance à être les mêmes, ils n'ajoutent aucun caractère unique au hachage.

Vous pouvez également utiliser une meilleure fonction de hachage comme MD5 (disponible dans Digest :: MD5) et ajuster le résultat à la taille désirée. Cependant, le fait que vous utilisiez un hash signifie que vous courez le risque d'une collision.

+3

La dernière phrase (hashing risk collision) vaut +1 tout seul. –

5

Avez-vous plus de 256 utilisateurs et/ou plus de 65536 cas de test par utilisateur? Si ce n'est pas le cas, vous pouvez simplement indexer les utilisateurs à partir de 0 .. 255 et tester les cas à partir de 0 .. 65535 et l'encoder sous la forme d'une chaîne de chiffres hexadécimaux afin que six caractères soient corrects. Si vous avez plus d'utilisateurs ou de cas de test, je indexerais à nouveau les utilisateurs et les cas de test, puis les combiner en un entier de 32 bits qui ne prendrait que 4 octets et serait trivial à implémenter mais légèrement plus difficile humains.

Dans tous les cas, je suppose que vous avez reçu un nom d'utilisateur et des informations sur les cas de test. Gardez simplement deux hachages liés: %users et %cases pour mapper les utilisateurs et les cas de test à leurs numéros d'index.

1

Si vous n'avez pas beaucoup d'utilisateurs/de test, une solution simple comme celle-ci pourrait suffire. Vous devriez ajouter la limite (et probablement emballer l'entier en le stockant).

[email protected]:~# more hash.pl 
use strict; 
use warnings; 

my %hash; 
my $count = 0; 

sub getUniqueId { 

     my $_user = shift; 
     my $_test = shift; 
     my $val; 

     my $key = $_user."|".$_test; 
     if (defined $hash{$key}) { 
       $val = $hash{$key}; 
     } else { 
       $hash{$key} = $count; 
       $val = $count; 
       $count = $count + 1; 
     } 
     return $val; 
} 

my @users = qw{ user1 user2 user3 user4 user5 user3 user5 }; 
my @testcases = qw{ test1 test2 test3 test1 test1 }; 

for my $user (@users) { 
     for my $test (@testcases) { 
       print "$user $test: ".getUniqueId($user,$test)."\n"; 
     } 
} 
[email protected]:~# perl hash.pl 
user1 test1: 0 
user1 test2: 1 
user1 test3: 2 
user1 test1: 0 
user1 test1: 0 
user2 test1: 3 
user2 test2: 4 
user2 test3: 5 
user2 test1: 3 
user2 test1: 3 
user3 test1: 6 
user3 test2: 7 
user3 test3: 8 
user3 test1: 6 
user3 test1: 6 
user4 test1: 9 
user4 test2: 10 
user4 test3: 11 
user4 test1: 9 
user4 test1: 9 
user5 test1: 12 
user5 test2: 13 
user5 test3: 14 
user5 test1: 12 
user5 test1: 12 
user3 test1: 6 
user3 test2: 7 
user3 test3: 8 
user3 test1: 6 
user3 test1: 6 
user5 test1: 12 
user5 test2: 13 
user5 test3: 14 
user5 test1: 12 
user5 test1: 12 
+1

Que croyez-vous exactement sortir de ce prototype? Vous voudrez peut-être lire le lien suivant avant d'en utiliser un autre: http://www.perl.com/language/misc/fmproto.html –

+0

Le problème du mélange des langues. J'avais écrit getUniqueId(), puis j'ai décidé de réparer le prototype plutôt que de le retirer. –

Questions connexes