我该如何在Perl中创建唯一标识符?

3
我正在创建一个以文件为导向的数据库,用于存储各个用户执行的一些测试结果。因此,我需要为数据库中的每个条目生成唯一的标识符。这些标识符必须满足以下要求:
  • 标识符应该相当小(最多6个字符)
  • 对于每个测试用例和用户组合,每次都应生成相同的标识符
我尝试使用种子值为31的简单BKDR哈希函数,并使用ord()函数如下:
@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" ;

有时会出现相同结果的情况,即不保证唯一性。有没有其他方法来实现唯一性?更改种子值是否有助于实现唯一性?
3个回答

5

你是否有超过256个用户和/或每个用户超过65536个测试用例?如果没有,您可以将用户从0 .. 255索引,将测试用例从0 .. 65535索引,并将其编码为十六进制数字字符串,因此六个字符就足够了。

如果您拥有更多的用户或测试用例,则再次对用户和测试用例进行索引,然后将它们组合成一个32位整数,实际上只需要4个字节,并且很容易实现,但对人类来说稍微困难一些。

无论如何,我假设您已经获得了用户名和测试用例信息。只需保留两个关联哈希表:%users%cases,以将用户和测试用例映射到它们的索引号。


3

你遇到的问题可能是使用了浮点数运算,而BKDR算法几乎肯定需要整数运算。你可以通过以下方式修复该错误:

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" ;

另一个可能有帮助的调整是使用除第一个和最后一个字符外的其他字符。 如果第一个和最后一个字符往往相同,则对哈希没有任何独特性。

您可能还想使用更好的哈希函数,例如MD5(在Digest :: MD5中可用),并将结果修剪为所需大小。 但是,使用哈希的事实意味着您可能会遇到碰撞的风险。


3
最后一句话(哈希风险冲突)本身就值得加1分。 - Michael Carman

1

如果您没有很多用户/测试用例,这样的简单解决方案可能已经足够了。您需要添加限制(并在存储时可能要打包整数)。

vinko@parrot:~# 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";
        }
}
vinko@parrot:~# 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
你认为从那个原型中你能得到什么?在使用另一个链接之前,建议先阅读以下链接:http://www.perl.com/language/misc/fmproto.html - Chas. Owens
混合语言的问题。我曾经写过getUniqueId(),然后决定修复原型而不是删除它。 - Vinko Vrsalovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接