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 V sum 程序有同样的问题。见段落。还是您在争论 sum 可以说是坏了?在这种情况下,它与 Perl 无关。 sum 的速度与您获得的一样快,尽管如上所述,它并不是非常强大。您可以通过使用大小来稍微改进它,例如$_ = &lt;&gt;; unpack("%32W*",$_)%65535 . length($_)。任何需要更健壮的东西都应该使用Digest::MD5Digest::SHA等。【参考方案3】:

不知道它有多快,但你可以试试String::CRC。

【讨论】:

以上是关于Perl 中的快速字符串校验和函数生成 0..2^32-1 范围内的值的主要内容,如果未能解决你的问题,请参考以下文章

如何以十六进制格式从 unpack 中获取校验和?

Perl 中字符串的最快校验位例程是啥?

如何使用 perl 的 pack 函数对字段重新排序

perl快速获得数字在数组中的排序

如何删除 vlookup 函数但实用地保留 perl 电子表格中的值

如何在 C# 中复制 Perl 的解包功能?