第 4 回 - Perl 入門(2)

[10/23, 2009 H.Aman]
67x27(1669bytes)   67x27(1669bytes) 【課題 2】

例題 2

テキストファイルを入力として, その中で次のパターンが登場する行のみを表示する Perl スクリプト find_pattern.pl を作りなさい:
(パターン)
数字が 1 文字以上登場し, その後ろに ax または by が登場する.途中に空白は入らない.」

例えば,

     8525ax           ... OK
     089927xxxx       ... NG(ax も by も登場しない)
     yyy089927byxxxx  ... OK(089927by が含まれる)
     xyzby            ... NG(byの直前に数字がない)

(実行例)

     $ perl find_pattern.pl foo.txt
     8525ax
     yyy089927byxxxx

解答例

     while ( $line = <> ){
        if ( $line =~ /\d+(ax|by)/ ){
           print $line;
        }
     }
     

解説

(1)数字
まず,「数字」というパターンをどうやって指定するか説明する.
数字ということは 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 という 10 種類の文字の中のどれかということになる.
これに対し,当然ながら if 文を 10 個書くというのは現実的でない.
この場合,「0 から 9 の中のどれか 1 つ」を表す便利なパターン表記がある:
     [0-9]
また,これは特別に
     \d
と書いてよいことになっている. そこで「1 桁の数字」を「\d」で表すことにする.

(2)1 回以上の登場
数字は \d で表現できるが, 問題文を見てみると "数字が 1 文字以上" となっていて, 具体的な文字数が与えられていない.
その場合は 「直前のパターンの 1 回以上の繰り返し」 を意味する「+」を使うとよい.
つまり,「数字が 1 文字以上登場する」というパターンは

     \d+
と書ける.

(3)ax または by の登場
複数の選択肢の中から一つを選ぶというパターンは, 各選択肢を「|」でつないで表す. ただし,選択肢の始まりと終りを明確に示すため ( ) で囲む:

     (ax|by)
もちろん,この書き方を(1)に適用してもよい:
     (0|1|2|3|4|5|6|7|8|9)
しかし,こちらの場合は \d と書くか [0-9] と書く方が圧倒的に容易であろう.
(参考)文字集合の表現
表記 意味
[asdf] a, s, d, f の中のどれか一文字
[^asdf] a, s, d, f 以外の一文字
[a-f] a, b, c, d, e, f の中のどれか一文字
[a-zA-Z_] アルファベット(小文字,大文字)または _ のいずれか一文字
\d 数字
\D 数字以外
\w 英数字または _ のいずれか一文字
\W 英数字でも _ でもない一文字
\s 空白文字(改行やタブも含む)
\S 空白文字(改行やタブも含む)以外
\d* 数字の 0 個以上の繰り返し(※\d 以外でも同様)
\d+ 数字の 1 個以上の繰り返し(※\d 以外でも同様)
\d? 数字が 0 個または 1 個(※\d 以外でも同様)
\d{3,10} 数字が 3 個以上 10 個以下(※\d 以外でも同様)
\d{3,} 数字が 3 個以上 (※\d 以外でも同様)
\+ + を表現したいとき( + だけだと直前のパターンを 1 回以上と誤解される)
他の特殊記号も同様: *, {, }, [, ], ^, $, ?