読者です 読者をやめる 読者になる 読者になる

ちょっとした文字列の成形をヒアドキュメントでやるなど

perl

本日3本目、昨夜からの24時間以内だと4本目にあたる更新です。
#べつにヒマなわけじゃないんですが・・書けそうだったので・・

時々、「ああこの20行程度のログ、一括でちょっとした処理したい〜」という時に(あるある!)、いちいち「処理するファイル(.pl)」と「素材テキストを入れたファイル(.txt)」を用意した上で、前者の処理用スクリプトをコチャコチャやるのも面倒というか、たぶんもちろん、プログラマの人たちはそういう時に普通に何かいい方法を使っておられるのだろうけど、でもぼくはまあ練習もかねてそういうことすることも少なくないのですが、

ふと結城浩さんのPerl本を読み返していたら、

新版Perl言語プログラミングレッスン入門編

新版Perl言語プログラミングレッスン入門編

ヒアドキュメントっていうのがあって(p35〜)、これを応用したら少し効率化できそうだな、と思って。

例としては、こんなログ的な文書があったとして(リアルなある一日のログをアレンジしたもの)、

[task>done]AさんにB送付することについてCと相談
[task]Dを読む
[task]E買ったことFに伝える
ハッシュリファレンスのデリフアレンスと普通のハッシュの参照の違いがわからない
帰宅
GとSkype。Hの件など
IはJの件でしんでるらしい
[task]Kさんにレス
[task>done]Lのリストを作る
MにNに関するレス完了
Oから何か来たっぽい
食器洗いの良い方法について書きたい
米とぎの良い方法しりたい
[done]風呂洗い
[done]PにQの修正依頼完了!
Rにレスしておこう
Rへのレス完了
[task>done]SにTの件、リマインド入れた。基本明日実行
いろいろあったな今日も。Uが来たり
vote.plのブログ書いてる
[task>done] 昨日までの作業のレビュー
[task]V案件のリスト作成
[task]WにXの方法を確認
[idea]昨日思いついたYのシステム
[task>done]Zにれす

これの、行頭にスクエア・ブラケット([ ]←これ)がある場合、それとその後の文字列との間に、タブスペースを入れたい、とか。そういうことがあるわけです。
#というのは、これをExcelにコピペしたときに、[ ]の内容はタグ的に別の列になってほしいから、ということなんですが。

さらに言うと、行頭にブラケットがない行についても、書式を揃えたいので、ママではなくて行頭に同じくタブスペースを入れたい、と。

#ようは、Excelに入れたときにこんなイメージにしたい、ということです。

[task>done] AさんにB送付することについてCと相談
[task] Dを読む
[task] E買ったことFに伝える
ハッシュリファレンスのデリフアレンスと普通のハッシュの参照の違いがわからない
帰宅
GとSkype。Hの件など
IはJの件でしんでるらしい
[task] Kさんにレス
[task>done] Lのリストを作る
MにNに関するレス完了
Oから何か来たっぽい
食器洗いの良い方法について書きたい
米とぎの良い方法しりたい
[done] 風呂洗い
[done] PにQの修正依頼完了!
Rにレスしておこう
Rへのレス完了
[task>done] SにTの件、リマインド入れた。基本明日実行
いろいろあったな今日も。Uが来たり
vote.plのブログ書いてる
[task>done] 昨日までの作業のレビュー
[task] V案件のリスト作成
[task] WにXの方法を確認
[idea] 昨日思いついたYのシステム
[task>done] Zにれす

んで、じゃあ上記のヒアドキュメントというのを使ってどうするかというと、まずこんなひな形を作って。

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

my $str = << "EOF";
EOF

if ($str =~ s///g) {
    print "$str\n";
}

で、その「"EOF"」と「EOF」の間に、処理したいテキスト群を入れて、if文以降をコチャコチャ書く。
そうすれば、処理ファイル(.pl)と素材ファイル(.txt)を分けずにこれ一個で済ませることができると。そういう風に考えまして。

んで、実際に上記の例に対して書いてみたのはこんな感じですが。

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

my $str = << "EOF";
[task>done]AさんにB送付することについてCと相談
[task]Dを読む
[task]E買ったことFに伝える
ハッシュリファレンスのデリフアレンスと普通のハッシュの参照の違いがわからない
帰宅
GとSkype。Hの件など
IはJの件でしんでるらしい
[task]Kさんにレス
[task>done]Lのリストを作る
MにNに関するレス完了
Oから何か来たっぽい
食器洗いの良い方法について書きたい
米とぎの良い方法しりたい
[done]風呂洗い
[done]PにQの修正依頼完了!
Rにレスしておこう
Rへのレス完了
[task>done]SにTの件、リマインド入れた。基本明日実行
いろいろあったな今日も。Uが来たり
vote.plのブログ書いてる
[task>done] 昨日までの作業のレビュー
[task]V案件のリスト作成
[task]WにXの方法を確認
[idea]昨日思いついたYのシステム
[task>done]Zにれす
EOF

if ($str =~ s/(\[.+\])(.+)/$1\t$2/g) {
    if ($str =~ s/\n([^\[].*)\n/\n\t$1\n/g) {
        print "$str\n";
    }
}

はい。で、後はこれをターミナルでそのまま実行するか、任意のファイルに書き出せばいいんですが、ただこれに限って言うと、実行すると・・

[task>done]	AさんにB送付することについてCと相談
[task]	Dを読む
[task]	E買ったことFに伝える
	ハッシュリファレンスのデリフアレンスと普通のハッシュの参照の違いがわからない
帰宅
	GとSkype。Hの件など
IはJの件でしんでるらしい
[task]	Kさんにレス
[task>done]	Lのリストを作る
	MにNに関するレス完了
Oから何か来たっぽい
	食器洗いの良い方法について書きたい
米とぎの良い方法しりたい
[done]	風呂洗い
[done]	PにQの修正依頼完了!
	Rにレスしておこう
Rへのレス完了
[task>done]	SにTの件、リマインド入れた。基本明日実行
	いろいろあったな今日も。Uが来たり
vote.plのブログ書いてる
[task>done]	 昨日までの作業のレビュー
[task]	V案件のリスト作成
[task]	WにXの方法を確認
[idea]	昨日思いついたYのシステム
[task>done]	Zにれす

ていう感じで、なんか惜しい。一部、行頭にタブスペースが入ってないんですよね・・(帰宅とか、Oとか米とぎとかRとか)

まあ、たぶん、というか100%、以下の処理部分に不備があるってことだとは思うのですが。

if ($str =~ s/(\[.+\])(.+)/$1\t$2/g) {
    if ($str =~ s/\n([^\[].*)\n/\n\t$1\n/g) {
        print "$str\n";
    }
}

ともあれ、この方法で行くと、冒頭に書いた「あ〜、パパッと処理したい!」という時に、この.plファイルを一個起動すれば、その中だけでほぼ完結する、ということで、いろいろ考える手間が省けるかなあ、と。

あとは副作用的に、こういうのを繰り返す中で正規表現の基礎みたいのに慣れつつある気はします。
(オチはない。正解も・・)