長岡 IT開発者 勉強会(NDS) 46回で「雑Perl」という話をしてきました #nds46

リラクヘルステック室の丸山です。

タイトルにある通り、2/20日に開催されたNDS46回で雑Perlというタイトルで発表をしてきました。リラク自体は関東に拠点を置く企業ですが、NDSは新潟県長岡市を拠点とした勉強会です。リラク自体が新潟と関連があるわけではないのですが、わたしが新潟とつながりが深く、そんな縁で今回は参加してきました。

わたしの発表内容

今回のテーマは「スクリプト言語」でした。弊社ではサーバーサイドのアプリケーションは基本的にScala、iOS向けアプリケーションはSwift/Objective-Cで書かれており、スクリプト言語がコアに使われているわけではないのですが、「雑にぱぱっとやっちゃいたい」みたいなときや、あるいは日々の運用などではRubyやPerlがよく使われています。そんなわけで、今回わたしは「雑Perl」というタイトルで、「雑にぱぱっとやる」ってときにPerlってすごい便利なんだよ〜。今回はふたつほどPerlの雑ポイントを紹介します!という内容の発表をさせていただきました。以下、その内容をブログエディションで紹介いたします。

ダイヤモンド演算子

Perlには、ダイヤモンド演算子<>というものがあり、この演算子を素で(なにも引数に与えずに)使うと、標準入力あるいは引数に与えたファイルから1行読み込みます。雑になにかを行いたいときはだいたい*nix系システムで行志向のファイルを雑に加工するとかそういうことをすることが多いと思うのですが、そういうときにこの挙動は便利です。

use strict;
use warnings;

while(my $line = <>) {
  $line =~ s/新潟/立川/g;
  print $line;
}

ファイルハンドルを開いているときの挙動

今から紹介する挙動はPerlを普段使っているひとにもよく「そういえばこういう挙動あったね〜」と言われるので、もしかしたらマイナーな挙動なのかもしれません。しかし、わたし的には「これいいよね〜」と思っている挙動なので、紹介します。

Perlでは、あるファイルを開いている途中でエラーメッセージが出力されるとき、「スクリプトファイルのn行目でエラーがあったよ」という情報だけではなく、「ファイルのn行目を読んでいる間でエラーがあったよ」という情報も表示してくれます。

たとえば、新潟市のオープンデータから、人口統計のファイルを見てみましょう。

一行目がヘッダ、2行目が合計、3行目以降に、年齢別の人口が記述されていることがわかるでしょう。これに対して何か雑に集計するためのPerlスクリプトを書くとします。すると、以下のようになるでしょう。

use strict;
use warnings;
use utf8;
use Text::CSV;

my $csv_file = shift;
open(my $fh, "<:utf8", $csv_file);

my $csv_reader = Text::CSV->new({ binary => 1 })
  or die "Cannot use CSV: ".Text::CSV->error_diag();

my $header_row = $csv_reader->getline($fh);
my $total_row  = $csv_reader->getline($fh);

while (my $row = $csv_reader->getline($fh)) {
  my $age_as_string = $row->[0];
  my $age = int($age_as_string);

  # do something with $age
}

close $fh;

open(my $fh, "<:utf8", $csv_file);でファイルを開き、そのファイルハンドルをText::CSVに渡して1行ずつ読み込んでなにかをしています。ここで、このプログラムに対してさきほどのオープンデータのcsvを食わせてみます。すると、以下のような出力が得られます。

Argument "100\x{6b73}..." isn't numeric in int at process_csv.pl line 17, <$fh> line 103.
Argument "\x{4e0d}\x{8a73}" isn't numeric in int at process_csv.pl line 17, <$fh> line 104.

process_csv.pl line 17という、「plファイルの17行目でエラーがあったよ」という情報だけではなく、 <$fh> line 103.というように、「読み込み中のファイルの103行目でエラーがあったよ」という情報も同時に出力されているのがみて取れるでしょう。実際、csvファイルの103行目の年齢カラムには、「100歳以上」という文字が書かれており、単純に数字として扱えないデータが入っています。

わたしは、Perl以外の言語で雑にファイルを処理していると、「あーなんか想定外の値が入ってきたせいでエラーになってるっぽいなー。どんな値が入ってきたんだろう……しょうがないなー。どこが原因なのか特定するため、ファイル1行読むたびにインクリメントする変数作るかー」みたいなことが多発します。だって雑だから。Perlだと、雑にこういうことしてても「ここやで(トントン)」みたいな感じで空気を読んでエラー報告してくれていいなー、なんて思うことが多いです。

そんなわけで、普段はScalaでアプリケーション書いているけれど、雑になんかするときにはPerl便利だよな、という話でした。

聴衆としておもしろかった話題

@civicさんによる発表でPythonのwith構文の話を聞いて、「これ便利だなー」と思いました。いわゆるloan pattern的なものは、クロージャがあれば簡単に自分でも実装できるのですが、言語がそういうのを提供してくれていない場合、それぞれのライブラリがそれぞれでloan patternを実装してたりして「うーむ」みたいな感じになるので、やっぱりこういうのは言語が用意してほしいなーという感じでありました。Javaならtry-with-resourcesがあるけどScalaにないんだよなー。

NDSでは毎回面白い話が聞けるので、地域的に近い方は、機会があればぜひ参加してみてはいかがでしょうか!