第 4 回 - Perl 入門(2)

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

例題 3

テキストファイルを入力として, その中で m で始まって s で終わる単語のみを出力する Perl スクリプト find_word.pl を作りなさい.

(実行例)

     $ perl find_word.pl ex3.txt
     managers
     measures
     metrics
     metrics
     metrics
     metrics
     metrics
     metrics
     managers
     metrics

解答例

     while ( $line = <> ){
         @words = split(/\b/, $line);
         foreach $w ( @words ){
             if ( $w =~ /^m.*s$/ ){
                 print $w, "\n";
             }
         }
     }
     

解説

(1)単語に分割
前回学んだ split 演算子を再び使用する.
今回は「単語の区切り」をパターンとして表現する必要があるが, Perl では特別に
     \b
が単語の区切りを表すことになっており,これを利用すればよい.
例えば,上述の回答例から if 文による条件分岐を無視し (# でコメントアウト),
     while ( $line = <> ){
         @words = split(/\b/, $line);
         foreach $w ( @words ){
#             if ( $w =~ /^m.*s$/ ){
                 print $w, "\n";
#             }
         }
     }
これを実行してみると split の働きが見えてくる:
     $ perl find_word.pl ex3.txt
     Given

     the

     central

       .....(中略)

     process

     improvement
     .
いちいち改行が入っているように見えるが, これは単語と単語の間の空白も切り出されているためである.
"Given the central " → 「Given」, 「(空白)」, 「the」, 「(空白)」,「central」

(2)m で始まって s で終わるパターン
やや込み入っているが,以下に示す if 文の条件部がこれに相当する:

     while ( $line = <> ){
         @words = split(/\b/, $line);
         foreach $w ( @words ){
             if ( $w =~ /^m.*s$/ ){
                 print $w, "\n";
             }
         }
     }
ここではパターンの記述に三つのポイントがある:
  • m で始まる → ^m
  • s で終わる → s$
  • 任意の文字列 → .*
(2-1)m で始まる
特別な表記として
     ^
は文字列の先頭を意味する. それゆえ ^m は文字列が「m で始まる」を意味する.

(2-2)s で終わる
特別な表記として

     $
は文字列の末尾を意味する(ただし,末尾が改行文字の場合はその前). それゆえ s$ は文字列が「s で終わる」を意味する.

(2-3)任意の文字列
一見すると

     ^ms$
と書けば「 m で始まって s で終わる」を意味するように見えるが, これは「ms」という単語にしかマッチしない.
m と s の間には任意の文字列が入ってもよいので, これについても書く必要がある.
特別な表記として
     . (ピリオド)
は任意の文字(つまり何でもよい)を意味する. よって, .* は「任意の文字が 0 個以上」=「任意の文字列」を意味する.

それゆえ,総合的には

     ^m.*s$ 
と書くことで目的のパターン「m で始まり s で終わる」を表現できる.

既に他の科目で学んだ内容であろうとは思うが, この種のパターン表現を正規表現という.
Perl では上述の例のように, 正規表現によるパターンマッチングを容易に実装できる.