Perl6:对 BagHash/Matching 感到困惑

Perl6: Confused about BagHash/Matching

我正在尝试使用 BagHash 计算正则表达式的匹配项,但得到了奇怪的结果。

my $fh = open "versions.txt";
my $versions = BagHash.new();

while (defined my $line = $fh.get) {
    my $last = '';
    if $line ~~ /(\d+)\.?(\d*)/ {
        say 'match ' ~ $/[0];
        if $last !eq  $/[0] {
            say 'not-same: ' ~ $/[0];
            $versions{$/[0]}++
        }
        $last = $/[0];
    }
    else {
        $last = '';
   }

}

say 'count: ' ~ $versions.elems;

输出为:

match 234
not-same: 234
match 999
not-same 999
count: 1 # I expect 2 here. 

我正在使用的测试用例是:

version history thingy

version=234.234
version=999

我错过了什么?

您将在每次迭代时重置 $last。另外,不要相信说。它旨在用于避免终端或日志文件被无限列表淹没。使用 dd(Rakudo 内部)或模块转储调试输出。如果您使用 dd 会看到 $/[0] 包含一个 Match,一个不适合生成哈希键的复杂结构。

# my @lines = slurp('version.txt');
my @lines = ('version=234.234', 'version=999');
my BagHash $versions.=new;
for @lines {
    ENTER my $last = '';
    if .Str ~~ /(\d+) '.'? (\d*)/ {
        $versions{[=10=].Str}++ if $last ne [=10=].Str;
        $last = [=10=].Str
    }else{
        $last = ''
    }
};

dd $versions;
# OUTPUT«BagHash $versions = ("234"=>1,"999"=>1).BagHash␤»

BagHash 的全部意义在于它的构造函数将为您进行计数。如果一直向下提供惰性列表,这会相当有效。

my @lines = ('version=234.234', 'version=999');
dd BagHash.new(@lines».split('=')».[1]);
# OUTPUT«("234.234"=>1,"999"=>1).BagHash␤»

Bug #1 是你几乎肯定希望你的 $last 声明在循环之外,这样你就不会一直将它重置为 ''

错误 #2 您可能只想更新 $last 在您发现并非所有行的版本号的状态下

错误 #3 您使用 Match 对象作为 HashBag 的键而不是版本的字符串值。您可以将匹配项强制为与 ~$/[0] 匹配的字符串,但 [=17=] 也是一种快捷方式。

我清理了您的代码并得到了以下有效的代码,但与惯用的 Perl 6 相去甚远:

my $fh = open "versions.txt";
my $versions = BagHash.new();

my $last = '';
for $fh.lines -> $line {
    if $line ~~ /(\d+)\.?(\d*)/ {
        say 'match ' ~ $/[0];
        if $last ne  $/[0] {
            say 'not-same: ' ~ $/[0];
            $versions{~$/[0]}++;
            $last = $/[0];
        }
    }
    else {
        $last = '';
   }

}
say $versions;
say 'count: ' ~ $versions.elems;

如果是丢弃代码,我个人会这样写:

my $versions = "versions.txt".IO.lines.comb(/(\d+)\.?(\d*)/).Bag; 
say $versions.elems;

如果您以后想要该文件或对每一行做更多的事情,或者这是为了生产:

my %versions;
for "versions.txt".IO.lines -> $line {
    if $line ~~ /((\d+)\.?(\d*))/ {
        %versions{[=12=]}++;
    }
}
say %versions.elems;