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;
我正在尝试使用 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;