こんの
今回は,主に正規表現を取り扱うことにします。
最初に正規表現の厳密な定義を書こうと思ったのですが, 非常に難解なため僕にも理解できないので, おおざっぱに説明します 1 2 。
いきなり「正規表現」という言葉を見ても 何をどう表現しているのか 意味が分かりにくいと思いますが, 簡単な例をあげて説明してみます。 例えば .public_htmlディレクトリ下に移動して
% ls
とすると,ファイル名のリストが得られます。 ファイル名の拡張子も様々だと思いますが,
% ls *.html
とすると,\texttt{html}という拡張子が ついたファイルのみのリストが得られたと 思います。(存在するのであれば) \texttt{cgi}という 拡張子がついたファイルはリストから除かれているはずです。 この処理では,リスト中のファイル名のうち, 「任意の文字列 + ピリオド + html」という パターンに一致するものだけを選んで表示しています。 つまり,
「○○.html」,「△△.html」,「□□.html」, ......
というふうに,いちいち羅列して指定しなくても 最後に.htmlがつくファイル名のみが 自動的に抽出されたわけです。
これは後で出てくる正規表現から見ると 例としては相当悪いかもしれませんが, 正規表現とはこのように, ある規則に基づいた,文字列のパターンの表現です。 「Aが最初に来て,1個以上3個以下のlが 続き,0個以上の文字が続いた後にwで終わる」と いった正規表現も可能です 3 例えば /usr/dict/wordsをこの正規表現にかけてみましょう。
% perl -ne 'print if /^al{1,3}\w*w$/' /usr/dict/words allow
今はこれの意味が分からなくても構いませんが, やっている内容は「/usr/dict/wordsという英単語がつまっている ファイルの中から,あるパターン(さっきのパターン)に一致するものを 検索して表示する」といったものです。 確かに「allow」は一致していますね。
正規表現のメタキャラクタはその文字そのものを 表わすのではありません。 例えば,この前出てきた「\n」は, 実は改行を表わすメタキャラクタです。 もしも「\n」という文字そのものを表わすのならば, 直後の1文字の特別な意味をなくすメタキャラクタ 「\」を用いて,「\\n」と書くことになります 4 。
それでは,主なメタキャラクタを掲げてみましょう。
メタキャラクタ(例) 一致するもの 単一の文字や数字にマッチするもの . 改行文字を除く任意の1文字 \d 1つの数字 \w アルファベットまたは数字(単語)の1文字 空白文字 \s 空白文字(スペース,タブ,改行) \n 改行 \r 復帰 \t タブ \e エスケープ文字 位置指定(アンカー) ^ 文字列の先頭 $ 文字列の末尾 繰り返しパターン x? 0個または1個のx x* 0個以上のx x+ 1個以上のx x{n,m} n個以上m個以下のx x{n,} n個以上のx x{n} n個のx abc 文字列中のabcというパターンにマッチ
実際にはここにあるもの以外にも 正規表現のメタキャラクタは存在するのですが, 機会があった時にでも追い追い説明していくことにします。
今回は正規表現によるパターン検索を行うので, 検索用の演算子のみ, ここで先に簡単に取り上げることにします。 その他の置換等の演算子は今度詳しくやります。
あるパターンPATTERNに 一致するかどうかを検索するには,
/PATTERN/
という検索演算子を用います。 この検索演算子とともに,スカラー $word について, パターンに一致することを示す演算子 =~ と 典型的なif文を用いれば,
(PATTERNに一致すれば 以下を実行する)といった構文が可能です。 また,逆にパターンに一致しないことを示す 否定の意の演算子 !~というのも存在し,if($word =~ /PATTERN/){...}
(PATTERNに一致しなければ 以下を実行する)といった構文も可能です。if($word !~ /PATTERN/){...}
ホームページに設置するカウンターには 様々なものがありますが, ここではとりあえず, ファイルから現在の来訪者を既に スカラー変数 $countに 読み込んであって, その値を表示させることにしましょう。 ただし,ただ数字を表示するだけでは面白くないので, 正規表現を用いて,人数の値に応じてthやstなどを 数字の後ろにつけることにしましょう。 検索の流れは以下の通りです。
ここでは,
if(式){ブロック}elsif(式){ブロック}...else{ブロック}
という条件分岐を用いることにします。 ちょっと elsifという文字に面食らいますが, まず if節が評価され, 次に elsif節が評価されていき, 最終的に残ったものが else節で評価されるという 流れになっています。
すると,最初に if節中で $countの 下2桁が「11」であるかどうかを 正規表現で検索することになります。 今までの知識を使うと, 文字列の末尾に「11」が並べばそれだけでいいわけですから, 「11$」となります。 つまり,
if($count =~ /11$/){...}
というわけですね 5 。
したがって,全ての検索を行って, 画面に表示させるまでのスクリプトは次のようになります。 ちなみに,スクリプト中で「#」以降は 行末までがコメントとみなされ,実行時には一切無視されます。
# $countには来訪者数の値が入っている。 if($count =~ /11$/){ # 下2桁が「11」ならば「-th」となる。 print "$count th\n"; }elsif($count =~ /12$/){ # 下2桁が「12」ならば「-th」となる。 print "$count th\n"; }elsif($count =~ /13$/){ # 下2桁が「13」ならば「-th」となる。 print "$count th\n"; }elsif($count =~ /1$/){ # 下1桁が「1」ならば「-st」となる。 print "$count st\n"; }elsif($count =~ /2$/){ # 下1桁が「2」ならば「-nd」となる。 print "$count nd\n"; }elsif($count =~ /3$/){ # 下1桁が「3」ならば「-rd」となる。 print "$count rd\n"; }else{ # 以上のいずれにも入らないならば「-th」となる。 print "$count th\n"; }
ただ,これだと出力が「1 st」のように なってしまって見苦しいので, 次回以降にその辺も含めて このスクリプトを改良したいと思います。
やっぱり「Perlリソースキット --UNIX版」高杉。
1) 詳しく知りたい人は,技術評論社「The UNIX Super Text【上】」の25.5節などを読んでみるとよいでしょう。
2) 【編註】情報科学科の人をつかまえると,「形式言語理論」のテキストを見せてもらえることでしょう。
3) 「^al{1,3}\w*w\$」かな。
4) ここでは \\と n での間に意味上の区切りがあることに注意しましょう。
5) なお,Perlでは if節等のブロック中の文が1つしかなくても,Cのようにブレース「{}」は省略できないので注意して下さい。
今野 俊一 (こんの, knn) <toknn@ijk.com>, <knn@ebony.plala.or.jp>
東京大学 工学部 計数工学科(内定), TSG(理論科学グループ)