2010-12-12
配列を比較したときの挙動、Perlの場合とRubyの場合
Perlの場合、配列がスカラコンテキストで評価されるので要素数が一致していれば真になる。
use strict; use warnings; my @array1=(1,2,3); my @array2=(1,2,4); if( @array1 == @array2){ print "true\n"; }else{ print "false\n"; }
このプログラムを実行すると、trueが返ってくる。
$ perl compare.pl true
array1=[1,2,3] array2=[1,2,4] if( array1 == array2) print "true\n" else print "false\n" end
このプログラムを実行すると、falseが返ってくる。
$ ruby compare.rb false
2010-12-07
KWIC索引の作成
プログラミング言語AWKに載っているKWIC(Keyword-In-Context)索引を作成するプログラムをperlに翻訳した。
ソースコード
use strict; use warnings; my @array=(); while(<>){ chomp; push @array, $_; for(my $i = length($_); $i >= 0; $i--){ if(substr($_, $i, 1) eq " "){ push (@array, substr($_,$i+1)."\t".substr($_,0,$i)); } } } @array = sort {lc $a cmp lc $b} @array; my $wid = 40; for(@array){ my @F=split(/\t/,$_); push @F,"" if(@F==1); printf("%".$wid."s %s\n", substr($F[1],length($F[1])-$wid), substr($F[0],0,$wid)); }
実行例
$ cat kwic.txt
All's well that ends well.
Nature abhors a vacuum.
Every man has a price.
$ perl kwic.pl kwic.txt
Every man has a price.
Nature abhors a vacuum.
Nature abhors a vacuum.
All's well that ends well.
All's well that ends well.
Every man has a price.
Every man has a price.
Every man has a price.
Nature abhors a vacuum.
Every man has a price.
All's well that ends well.
Nature abhors a vacuum.
All's well that ends well.
All's well that ends well.
2010-12-06
Perlによるワンライナー
ワンライナーを書くときに便利なオプション
-e オプション
続く文字列をワンライナーだと認識させる。シェルによる解釈を防ぐためにシングルクォートで囲む。
$ perl -e 'print "hello world\n"' hello world
-n オプション
プログラム全体をwhile(<>){...}で囲ったものと同じ効果が得られる。
$ perl -ne 'print "$_\n"' input.txt
は
while{<>}{ print "$_\n" }
を実行させたのと同じである。
-l オプション
出力に改行文字をつける。
$ perl -ne 'print "a \n"' input.txt
は
$ perl -nle 'print "a "' input.txt
-a オプション
@F=split(/ /,$_)と同じ意味。デフォルトの変数$_をスペースで区切って@Fに格納。awkのようなカラム処理をするときに必要。
$ perl -nle '@F=split(/ /,$_); print "$F[0]"' input.txt
は
$ perl -nlae 'print "$F[0]"' input.txt
と同じ意味。
-F オプション
デフォルトでは、-aオプションの区切り文字はスペースだが、それを変更したいときに使う。
$ cat input.txt 1,2,3 4,5,6 $ perl -F, -nlae 'print $F[0]' input.txt 1 4
ワンライナー20例
プログラム言語AWKに載っている"便利 な「一行野郎」たち"をperlに翻訳した。awkによる例とともに示す。
1. 入力行の総数を出力する
$ awk 'END{print NR}' input.txt
$ perl -nle 'END{print $.}' input.txt
awkでは行番号はNRに格納されているのに対し、perlでは$.に格納されている。
2. 10行目の入力行を出力する
$ awk 'NR == 10' input.txt
$ perl -nle 'if($. == 10){print }' input.txt
awkは'パターン{アクション}'という構文をとるのだが、アクションが入力行をそのまま出力する、つまり、{print $0}の場合は省略できるので、非常にシンプルに書ける。perlではprint文の対象が$_の場合、省略ですることができる。
3. すべての入力行の最後のカラムを出力する
$ awk '{print $NF}' input.txt
$ perl -nlae 'print $F[-1]' input.txt
awkではNFがカラム数を格納する変数なので、最後のカラムは$NFで参照できるのに対し、perlでは$F[-1]を使って参照している。
4. 最後の行の最後のカラムを出力する
$ awk '{f = $NF} END{print f}' input.txt
$ perl -nlae '$f = $F[-1]; END{print $f}' input.txt
5. カラム数が4を超える行を出力する
$ awk 'NF > 4' input.txt
$ perl -nlae 'if(@F > 4){print }' input.txt
6. 最後のカラムの値が4を超えるようなすべての行を出力する
$ awk '$NF > 4' input.txt
$ perl -nlae 'if($F[-1] > 4){print }' input.txt
7. すべての入力行のカラムの総数を出力する
$ awk '{c += NF}END{print c}' input.txt
$ perl -nlae '{$c += @F}END{print $c}' input.txt
perlでは配列をスカラコンテキストで評価すると要素数が返ってくる。
8. Bethを含む行の総数を出力する
$ awk '/Beth/{sum++}END{print sum}' input.txt
$ perl -nle 'if(/Beth/){$sum++}END{print $sum}' input.txt
9. 第一カラムが最も大きな行を出力する(第一カラムのうち少なくとも1つは正の数であると仮定)
$ awk '$1 > max{max = $1; ml = $0}END{print ml}' input.txt
$ perl -nlae 'if($F[0] > $ml[0]){@ml = @F}END{print "@ml"}' input.txt
10. 少なくとも1つのカラムをもつ行をすべて出力する
$ awk 'NF > 0' input.txt
$ perl -nlae 'if(@F > 0){print }' input.txt
11. 80文字以上の長さを持つ行をすべて出力する
$ awk 'length($0) >= 80)' input.txt
$ perl -nle 'if(length($_) >= 80){print }' input.txt
12. 行のカラム数とその行自体を出力する
$ awk '{print NF, $0}' input.txt
$ perl -nlae 'print scalar(@F)," $_"' input.txt
13. すべての行の最初の2つのカラムを逆順で出力する
$ awk '{print $2, $1}' input.txt
$ perl -nlae 'print "$F[1] $F[0]"' input.txt
14. すべての行の最初の2つのカラムを逆順にしてすべてのカラムを出力する
$ awk '{t = $1; $1 = $2; $2 = t; print }' input.txt
$ perl -nlae '($F[0], $F[1]) = ($F[1], $F[0]); print "@F"' input.txt
15. すべての行を最初のカラムを行番号に置き換えて出力する
$ awk '{$1 = NR; print }' input.txt
$ perl -nlae '$F[0]=$.; print "@F"' input.txt
16. すべての行の2つ目のカラムを消去して出力する
$ awk '{$2 = ""; print}' input.txt
$ perl -nlae 'splice(@F,1,1); print "@F"' input.txt
17. すべての行のカラムを逆順で出力する
$ awk '{for(i = NF; i > 0; i--){printf("%s ", $i)}printf("\n")}' input.txt
$ perl -nlae '@F=reverse @F; print "@F"' input.txt
awkの方が長くなってしまう。perlにはreverse関数があるので簡潔に書ける。
18. すべての行の各カラムの合計を出力する
$ awk '{sum = 0; for(i = 1; i <= NF; i++){sum += $i}print sum}' input.txt
$ perl -nlae '$sum=0; for(@F){$sum += $_}print $sum' input.txt
19. すべての行のすべてのカラムを合計してその値を出力する
$ awk '{for(i = 1; i <= NF; i++){sum += $i}}END{print sum}' input.txt
$ perl -nlae 'for(@F){$sum += $_}END{print $sum}' input.txt
20. 各カラムの値を絶対値に置き換えてからすべての行を出力する
$ awk '{for(i = 1; i <= NF; i++){if($i<0){$i *= -1}}print }' input.txt
$ perl -nlae '@F = map{abs($_)} @F; {print "@F"}' input.txt
perlには絶対値を返す関数absがあるが、awkにはない。perlではmap関数を使うことにより簡潔にかける。
後半の、for文を使うようなものではperlの方が短くなった。
