Perl 中的快速字符串校验和函数生成 0..2^32-1 范围内的值
Posted
技术标签:
【中文标题】Perl 中的快速字符串校验和函数生成 0..2^32-1 范围内的值【英文标题】:A quick string checksum function in Perl generating values in the 0..2^32-1 range 【发布时间】:2010-12-29 02:35:09 【问题描述】:我正在寻找具有以下属性的 Perl 字符串校验和函数:
输入:未定义长度的 Unicode 字符串 ($string
)
输出:无符号整数 ($hash
),其中 0 <= $hash <= 2^32-1
持有(0 到 4294967295,匹配 4 字节 mysql 无符号整数的大小)
伪代码:
sub checksum
my $string = shift;
my $hash;
... checksum logic goes here ...
die unless ($hash >= 0);
die unless ($hash <= 4_294_967_295);
return $hash;
理想情况下,校验和函数应该能够快速运行,并且应该在目标空间 (0
.. 2^32-1
) 中生成稍微一致的值以避免冲突。在这个应用程序中,随机碰撞是完全非致命的,但显然我想尽可能避免它们。
鉴于这些要求,解决此问题的最佳方法是什么?
【问题讨论】:
您想避免与所有可能的字符串发生冲突,但只有 40 亿个可能的摘要?为什么使用整数很重要?即使您必须将摘要存储为字符串,使用 MD5 之类的东西怎么样? “您想避免与所有可能的字符串发生冲突” - 不,正如问题中所述,我只是“想尽可能避免它们”。 “为什么使用整数很重要?” - 如问题所述,校验和将存储在“4字节MySQL unsigned int”中。 【参考方案1】:任何散列函数就足够了 - 只需将其截断为 4 字节并转换为数字。好的哈希函数有一个随机分布,无论你在哪里截断字符串,这个分布都是恒定的。
我建议Digest::MD5,因为它是标准 Perl 中最快的哈希实现。正如 Pim 提到的,String::CRC 也是用 C 实现的,应该更快。
以下是计算哈希并将其转换为整数的方法:
use Digest::MD5 qw(md5);
my $str = substr( md5("String-to-hash"), 0, 4 );
print unpack('L', $str); # Convert to 4-byte integer (long)
【讨论】:
B::hash 也自带core perl,使用内部core hash 函数,比MD5 快,返回一个hexified 32-bit integer。但不如 MD5 安全。【参考方案2】:来自perldoc -f unpack
:
For example, the following computes the same number as the
System V sum program:
$checksum = do
local $/; # slurp!
unpack("%32W*",<>) % 65535;
;
【讨论】:
所有位的 32 位总和对于随机分布来说是一个非常糟糕的哈希值。任何哈希函数都更好,即使是最简单的。 当然,但这与 System Vsum
程序有同样的问题。见段落。还是您在争论 sum
可以说是坏了?在这种情况下,它与 Perl 无关。
sum
的速度与您获得的一样快,尽管如上所述,它并不是非常强大。您可以通过使用大小来稍微改进它,例如$_ = <>; unpack("%32W*",$_)%65535 . length($_)
。任何需要更健壮的东西都应该使用Digest::MD5
或Digest::SHA
等。【参考方案3】:
不知道它有多快,但你可以试试String::CRC。
【讨论】:
以上是关于Perl 中的快速字符串校验和函数生成 0..2^32-1 范围内的值的主要内容,如果未能解决你的问题,请参考以下文章