ノンプログラマーのためのPerl 〜 forと正規表現を使ったお得なセット

こんにちは。こちらはPerl入学式アドベントカレンダーの20日目の記事です。
(おっと日付が……🙇)

qiita.com

はじめに

あらためまして、まずここで「Perl入学式」について簡単に説明しておきますと、Perl入学式とは、Perlまたはプログラミング自体の未経験者に、Perlを通してプログラミングの基礎をお教えしましょう、という無料のプログラミング講座です。
www.perl-entrance.org

ぼくも2013年の8月、同年度第3回の補講から、まったく素人の状態で生徒として参加しまして、
Perl入学式#3補講に行ってきた - 103

その翌年春からはサポーター(運営側)に加わっています。

……といっても最近は地理的な問題などもあり、リモート参加が大半なのですが。
継続的に現場で開講しているメンバーの皆さんには、本当に敬服するばかりです。

さて本日は、ぼくのようなノンプログラマー、つまり普段の仕事ではプログラミングとは関係のないことをしている人*1が、プログラミング言語Perlを学ぶことによって、どんな便利なことになるのか、みたいな話をします。

といっても、その便利さをすべて説明しようとしたら大変な時間と文章量が必要になりますので、今回はその中でもとくに「これは」というところに絞って説明します。

for文

多くの場合、ぼくが普段の仕事をしているときに、「んー、こりゃプログラミングの力を借りた方がよさそうだな!」と思うのは、

テキストファイルAの内容に何らかの処理を加えて、テキストファイルBとして保存する

みたいなことをやりたい時です。

具体例を挙げてみると、たとえば以下のような名簿があったとして、

ジョン・レノン
ポール・マッカートニー
ジョージ・ハリスン
リンゴ・スター

このすべての文末に敬称「さん」を付けたい、という場合。

いやもちろん、このぐらいなら自分で書けばいいんですが、これが何百人もいたら大変なので……ということ。

こんなとき、ぼくだったらこんなコードを書きます。

#!/usr/bin/env perl
use strict;
use warnings;

my @band = qw/
ジョン・レノン
ポール・マッカートニー
ジョージ・ハリスン
リンゴ・スター
/;

for my $member (@band) {
    print "$memberさん\n";
}

まず配列 @band に4人の名前を入れて、これをforループで回しつつ、出力時に「さん」を加えています。

実行してみると……
gyazo.com

はい、できました。for文、めっちゃ便利ですね。

このfor文については、Perl入学式の講義資料より以下をご参照ください。
https://github.com/perl-entrance-org/workshop-2017/blob/master/2nd/slide.md#for文-配列

qwについては以下をどうぞ。
https://github.com/perl-entrance-org/workshop-2017/blob/master/2nd/slide.md#qw-ショートカット

if文、正規表現

さてしかし、現実の世界では、このように元のデータすべてに同じ処理をするという機会はそうそうなくて、この内の「ある条件に合致するもの」だけに処理を加えたい、ということが多いです。

たとえば、この中で名前の最後に「ン」が付く人だけ敬称を「様」にしたい、という場合にはどうすればいいでしょうか?

そのような時には、こう書きます。

#!/usr/bin/env perl
use strict;
use warnings;

my @band = qw/
ジョン・レノン
ポール・マッカートニー
ジョージ・ハリスン
リンゴ・スター
/;

for my $member (@band) {
    if ($member =~ /\z/) {
        print "$member\n";
    }
    else {
        print "$memberさん\n";
    }
}

実行。
gyazo.com

はい、できました。

このif文と、それに付いてくる正規表現(「=~」とか「//」を使って色々やっているもの)については、同じくPerl入学式の講義資料から以下をご参照ください。

if文
https://github.com/perl-entrance-org/workshop-2017/blob/master/2nd/slide.md#if-else文

正規表現
https://github.com/perl-entrance-org/workshop-2017/blob/master/4th/slide.md#正規表現

__DATA__

さてここで、一旦冒頭の話に戻りますが、普段の仕事(プログラミングとは関係ないそれ)をしていて、時々欲しくなるのは、

テキストファイルAの内容に何らかの処理を加えて、テキストファイルBとして保存する

という能力です。

上の例でいうと、テキストファイルAにあたるのは

ジョン・レノン
ポール・マッカートニー
ジョージ・ハリスン
リンゴ・スター

で、処理後のテキストファイルBにあたるのは

ジョン・レノン
ポール・マッカートニーさん
ジョージ・ハリスン
リンゴ・スターさん

になります。

ただ、さすがにこんな風に、処理したいデータ(ここではその4名)を毎回コードの中に埋め込むというのは面倒というか、できればコードはコード、素材データは素材データとして分けて扱いたいので、上記に加えてぼくが多用するのが「__DATA__」という記法*2です。

さっそく、それを使って書き換えてみましょう。

#!/usr/bin/env perl
use strict;
use warnings;

my @band = <DATA>;

for my $member (@band) {
    chomp $member;
    if ($member =~ /\z/) {
        print "$member\n";
    }
    else {
        print "$memberさん\n";
    }
}

__DATA__
ジョン・レノン
ポール・マッカートニー
ジョージ・ハリスン
リンゴ・スター

はい。だいぶスッキリしました。
結果は先ほどと同じですが、一応実行してみましょう。
gyazo.com

いいですね。
こうすることによって、対象のデータがいくら変わっても、それは「__DATA__」より下の部分で書き換えればよくなり、それより上のコード部分を触る必要がなくなります。

また、この方法だと1本のスクリプトファイルで完結するので、コードもデータもそれぞれ手軽に書き換えられて便利です。

じつのところ、ぼくが普段の仕事に関連して書くコードの大半は、これのバリエーションです。

たとえば、少し前に、別のアドベントカレンダーでこんな記事を書いたのですが、
note103.hateblo.jp

この後半で紹介している、本の脚注データを分析するコードにしても、途中でハッシュを使ったりはしていますが、基本形は上記と同じであることがわかるかと思います。

実際には、もう少し踏み込んだことをしようとすると、コードとは別に置かれた素材ファイルを読み込んだり、結果を別のファイルに書き出したり、あるいは任意のディレクトリにあるファイルを読み込んだりもしたくなってくるのですが、まずは上記のようなことができるだけでも、かなりいろんな作業が効率化するので、入門者の方は試しにこれらのセット(for + if + 正規表現 + __DATA__)を自分の環境で動かしてみてはいかがでしょうか?

ちなみに、環境構築を含む第1回からの講義資料は、以下にまとまっています。
講義資料 - Perl入学式 | Perl Entrance

ということで、本日の記事は、以上です。

明日の……ではなくて、本日のご担当はgomaaaさんです!

Perl入学式のアドベントカレンダー、ひき続き、お楽しみに。
qiita.com

*1:ぼく自身は本の編集をしています。より詳しくはこちらをどうぞ。→ note103 - note103 - Scrapbox

*2:『初めてのPerl(第6版)』によると、厳密には「ファイルハンドル」と呼ばれるようです。ファイルハンドルとは、Perlの処理世界と外部世界(おそらく素材のテキストデータなど)を結びつけるコネクションの名前、とのこと。詳しくは同書をどうぞ。

初めてのPerl 第6版

初めてのPerl 第6版