0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Perl 6Advent Calendar 2016

Day 4

Perl 6でNLP 5本ノック 『第2章: UNIXコマンドの基礎』 10 ~ 14

Last updated at Posted at 2016-12-03

こんにちは、Perl 6アドベントカレンダーの四日目の投稿になります。

NLP 5本ノックということで、東北大学の言語処理100本ノックの『第2章: UNIXコマンドの基礎』の 10~14までの5本をPerl 6で解きつつ解説をしていきたいと思います。

問題文は掲載しませんので、ブラウザの別窓で下記ページを参照しながらお楽しみください:
http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch2

読み進める前に

注意!

  • 読者レベルとしては、Perl 6アドベントカレンダー1日目で紹介したPerl 6 introductionなどのチュートリアルを一通り終えたレベルを想定しています。
  • わかりやすく紹介するために、正確ではない表現がところどころ出てくるかもしれません。
  • より正確な情報を知りたい場合は、Perl 6アドベントカレンダー1日目で紹介した公式ドキュメント や公式テストケースのroastなどを参照ください。
  • 日本語訳が定着していないようなPerl 6独特の英単語を目にするかもしれません。基本的に解説中ではそのまま英単語で書き、その後補足しますのでご容赦ください。
  • Perl 6のモットーはTMTOWTDI (やり方は一つじゃない) です。特に正解はありません。でも、「これのほうがもっとかっこよく簡潔に書けるよ!」といった指摘は大歓迎です!
  • 《一列目の要素》といった表記が出てくるかと思いますが、 "《"や"》"は単に強調のために使っているだけでありPerl 6自身の文法ではないので注意してください。

10. 行数のカウント

コード

10.p6
$*IN.lines.elems.say;

解説

  1. $*IN.lines で標準入力を受け取り、遅延リストを生成します
  2. .elemsでinvocantのリストの要素数を算出します
  3. .sayで要素数を出力します

補足

11. タブをスペースに置換

コード

11.p6
.trans("\t" => " ").say for $*IN.lines;

解説

  1. for $*IN.linesで標準入力の各行を走査していきます
  2. .trans("\t" => " ")でinvocant(i.e. 行の文字列)に含まれるタブを半角スペースに変換します
  3. .sayで出力します

12. 1列目をcol1.txtに,2列目をcol2.txtに保存

コード

12.p6
my $col1-fh = open("col1.txt", :w);
my $col2-fh = open("col2.txt", :w);
my @col1-col2 = $*IN.lines.map: { .split("\t")[0,1] };

$col1-fh.say(@col1-col2>>.[0].join("\n"));
$col2-fh.say(@col1-col2>>.[1].join("\n"));
$col1-fh.close;
$col2-fh.close;

解説

  1. open("col1.txt", :w) で書き込み専用モードのIO::Handleオブジェクトを生成し変数に代入します
  2. open("col2.txt", :w) で書き込み専用モードのIO::Handleオブジェクトを生成し変数に代入します
  3. $*IN.lines.map で標準入力の各行を変換して、リストにします。map内のポインティブロックでは下記のような操作がおこなわれます
  4. 標準入力の各行をsplit("\t")でタブ文字で分割してリストにします
  5. 1列目と2列目だけを抜き出して、(《1列目の要素》,《2列目の要素》)のリストを生成します
  6. $col1-fh.say(《TEXT》)col1.txtに《TEXT》の書き込みをします
  7. @col1-col2>>.[0]で《1列目の要素》だけを抜き出してリストにします
  8. .join("\n")で改行区切りでinvocantを結合します
  9. $col2-fh.say(《TEXT》)col2.txtに《TEXT》の書き込みをします
  10. @col1-col2>>.[1]で《2列目の要素》だけを抜き出してリストにします
  11. .join("\n")で改行区切りでinvocantを結合します
  12. .closeでファイルハンドルを閉じます

13. col1.txtとcol2.txtをマージ

コード

13.p6
my $col1-fh = open("col1.txt", :r);
my $col2-fh = open("col2.txt", :r);

.say for ($col1-fh.lines Z $col2-fh.lines)>>.join("\t");
$col1-fh.close;
$col2-fh.close;

解説

  1. open("col1.txt", :r) で書き込み専用モードのIO::Handleオブジェクトを生成し変数に代入します
  2. open("col2.txt", :r) で書き込み専用モードのIO::Handleオブジェクトを生成し変数に代入します
  3. ($col1-fh.lines Z $col2-fh.lines)で1列目と2列目をZip演算子で結合します
  4. >>.join("\t")でリストの各要素をタブで結合します
  5. .closeでファイルハンドルを閉じます

補足

14. 先頭からN行を出力

コード

14.p6
sub MAIN(Int :$N!) {
    .say for gather for $*IN.lines { take $_ }.head($N);
}

解説

  • sub MAINを使うとコマンドライン引数を受け取とれるようになります
    • :$N!!はrequiredの意味です。つまり必須オプションです。 ちなみに?だと任意のオプションになります。
  1. gather for take イディオムで遅延リストを生成します
    • $*IN.lines { take $_ } で各行を取り出します
  2. .head($N) でコマンドライン引数Nで与えた値と同数の行を遅延リストの先頭から抜き出します
  3. .say for 《.head($N)の返したリスト》 で各行を出力していきます

補足

  • MAINについて詳しく知りたい場合は次のページを参照してください:https://docs.perl6.org/language/functions#sub_MAIN
  • もっと親切なヘルプメッセージを出したいと思った方もいるでしょう。そういう場合はsub USAGEを使うとよいです。つぎのページを参照するとよいでしょう。:https://docs.perl6.org/language/functions#sub_USAGE
    • 実際のアプリケーションだとzefやpandaなどのUSAGEの使い方が参考になるでしょう

以上、Perl 6でNLP 5本ノック 『第2章: UNIXコマンドの基礎』 10 ~ 14 でした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?