2016-08-13 9 views
2

BagHashを使って正規表現の一致を数えようとしていて、奇妙な結果を得ようとしています。Perl6:BagHash/Matchingについて混乱しています

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 

私は何をしないのですか?

+0

'!='は両方の引数を 'Num'に強制します。あなたはそれが欲しいですか? –

+0

私はしませんでした!しかし、それは問題を引き起こしているものではないようです。私はちょうど実行した新しいバージョンを反映するように編集しました。 –

答えて

4

各繰り返しで$ lastをリセットしています。また、信じてはいけません。ターミナルやログファイルを無限のリストで氾濫させないために使われます。デバッグ出力をダンプするにはdd(Rakudo internal)またはモジュールを使用してください。 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{$0.Str}++ if $last ne $0.Str; 
     $last = $0.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␤» 
+0

'»'演算子には同時並行したセマンティクスがあります。 – raiph

+0

この仕様では、ハイパープットが熱心であるか怠惰であると要求していません。それらは並行として定義されます。 –

+0

実際には、ハイパーは怠惰な熱心なスケールの別のノッチのようです。ハイパーは熱心な人よりも「eagerrer」でもあり、少なくともハイパーは熱心であることを意味します。 – timotimo

4

バグ#1あなたはおそらく唯一の場所な状態に$lastを更新したい''

バグ#2にリセット保持しませんので、あなたはほぼ確実にループの外であなたの$last宣言をしたいですすべての行ではないバージョン番号を見つけました

バグ#3バグ#3は、バージョンの文字列値ではなく、HashBagのキーとしてMatchオブジェクトを使用しました。一致した文字列は~$/[0]と一致しますが、$0のショートカットだけです。

私はあなたのコードをクリーンアップし、以下のように動作しましたが、かなり遠く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{$0}++; 
    } 
} 
say %versions.elems; 
+1

私はまた、 '/(\ d +)[\。 (\ d +)]?/'おそらくここで欲しいものです。 'my%versions is BagHash;'、 'my%versions:= ...'も使用します。 –

+0

非常に明確です、ありがとうございます。 Bug#2はバグではありませんが、正規表現にマッチする行のクラスタです(おそらく、同じ10進数の前にある複数の連続した行)。同じ値を持つクラスタを数えたい - テストケースが単純化されました。 –

関連する問題