使用 Fletcher-16 哈希算法生成唯一的模块名称

作者:Daniel Carrera

一个基于 Fletcher-16 哈希算法为 Perl 模块计算唯一文件名的程序草案。

许可证:公共领域

示例:Foo::Bar-auth:92de-ver:1.2.0--0

说明

模块名称 (Foo::Bar) 经过 URL 编码。之后,我们添加按键排序的所有元数据。版本号保持不变。其他元数据使用 Fletcher-16 进行哈希处理。

最后,在末尾添加一个计数器。如果两个不同的模块获得了完全相同的名称(极不可能),我们会使用计数器来区分它们。

源代码:Fletcher.pl

use v6;

my @modules = (
    {name => "Foo::Bar", meta => {auth=>'mailto:[email protected]', ver=>'1.2.0'}},
    {name => "Foo::動", meta => {auth=>'mailto:[email protected]', ver=>'2.1.3'}}
);

say filename(@modules[0]<name>,@modules[0]<meta>);
say filename(@modules[1]<name>,@modules[1]<meta>);

sub filename($module,%meta) {
    my $filename = strencode($module);
    for %meta.sort {
        my $v = .value ~~ m/[\D & <-[.]>]/ ?? fletcher16(.value) !! .value;
        $filename ~= "-" ~ .key ~ ":$v";
    }
    return $filename ~ "--0";
}

sub strencode($str) {
    return $str.subst(/(<-alpha -[:]>)/,{ charencode($0) },:g);
}

sub charencode($char) {
    my ($url,$hex) = ('',$char.fmt("%02x"));

    while $hex.chars {
        $url ~= '%' ~ $hex.substr(0,2);
        $hex = $hex.substr(2);
    }
    return $url;
}

sub fletcher16($str) {
    my ($A,$B) = (0,0);
    for map { .ord }, $str.comb -> $val {
        if $val > 255 {
            $A = ($A + $val div 255) % 255;
            $B = ($B + $A) % 255;
        }
        $A = ($A + $val % 255) % 255;
        $B = ($B + $A) % 255;
    }
    return ($A*256 + $B).fmt("%04x");
}