【Perl】1行分の文字列から、パターンにマッチする回数をカウントするワンライナーほか
投稿日: / 更新日:
この記事は2年以上前に書かれたものです。情報が古い可能性があります。
例えば、次のような1行の文字列から、hello
の出現回数を調べたい場合、
1 |
hello1, hello2, hello3, hello4, hello5 |
正規表現のグローバルマッチ(g
フラグ)を使用することになりますが、今までは大体次のようなワンライナーを書いていました。
1 2 |
$ echo "hello1, hello2, hello3, hello4, hello5" | perl -nle '$count++ while /hello/g}{print $count||0' 5 |
ちなみに、}{
は[Eskimo greeting](http://search.cpan.org/perldoc/perlsecret#Eskimo_greeting)という慣用句で、これよりも右に書いたコードがあたかもワンライナーのEND
ブロックのように働き、-p
や-n
スイッチで標準入力の各行に対して行った処理の後処理を行うことができます。上記のワンライナーでは、hello
にマッチした都度カウントアップした$count
の値を、最後に標準出力へ出力する処理を行っています。
上記のワンライナーを、[Goatse](http://search.cpan.org/perldoc/perlsecret#Goatse)という慣用句を使うことでさらに短く書ける、ということを今回知りました。これにより、ワンライナーを次のように書き直すことができます。
1 2 |
$ echo "hello1, hello2, hello3, hello4, hello5" | perl -nle '$count=()=/(hello)/g}{print $count' 5 |
上記のコードのうちの=()=
がGoatseです。これは、右側のリスト代入を左側でスカラー変数へ代入(すなわち、スカラーコンテキストで評価)することによって、そのリストの要素数が得られる、というPerlの言語仕様を利用しています。結果として、リストの要素は破棄され、要素数が$count
へ代入されます。なお、リストを単純にスカラーコンテキストで評価した場合には、リストの最後の要素しか得られないため、真ん中のかっこ(()
)が重要となります。
これにより、1つもマッチしなかった場合に0にするコード(||0
)も含め、従前のワンライナーに比べて6文字も減らすことができました。ただし、マッチした部分をキャプチャーしなければならないこと、また、何をやっているかが(慣れるまで)分かりにくいこと、がデメリットです。
あと、参考までに、hello
の後の数値の合計を出力するワンライナーをご紹介します。
1 2 |
$ echo "hello1, hello2, hello3, hello4, hello5" | perl -nle '$sum+=$1 while /hello(\d+)/g}{print $sum||0' 15 |
こちらは、数値(\d+
)の部分を加算するためにキャプチャーする必要があります。最初のワンライナーと同様、グローバルマッチとEskimo greetingを使用します。Goatseは使用しません。
以上、簡単ですがPerlに関する話題をご紹介しました。