電話帳や郵便番号簿から目的のデータを探すときはどうするだろう。 おそらく先頭から1〜2文字(イニシャル)を利用して、検索ボタンなり索引を使っ て探すだろう。誰が登録されているか覚えていれば良いが、未知のものから探す のはたいへんである。また、データの先頭の文字を忘れていたり、 「サトウ」なのか「サイトウ」なのかとか、 「イカラシ」なのか「イガラシ」なのかなど、途中があやふやだったりすると 検索ではできない。
なにかを検索するときに、そのデータに含まれている文字列のパターンを 汎用的に指定する方法がある。そのうち、もっとも一般的であるものが 正規表現である。
たとえば、「サトウ」と「サイトウ」どちらかを探したい場合、 正規表現では次のように検索パターンを書く。
サイ?トウ
こうすると、"サトウ" または "サイトウ" 両方にマッチするようになる。
特別な文字 ?
を指定すると、「その直前の文字があっても無くても
いい」という指定になる。また、別の特別な文字 [ ]
を使っても、
同様の指定ができる。たとえば、
イ[カガ]ラシ
とすると、"イカラシ" でも "イガラシ" でもマッチするようになる。
特別な文字 [ ]
の中に何文字か文字を列挙すると、
その中のどれかの文字が来ればいい、という指定になる。
上記の正規表現の例は特殊な文字の働きを分かりやすくために最も単純に書 いたものであり、実際にRubyプログラムに正規表現を書くときはそのままでは 使えないので注意すること。
egrep
コマンドによる正規表現の実験
実際に名簿のようなデータを作って、正規表現で検索する練習をしてみよう。
最初に検索のデータとなるファイルを作っておこう。以下のような名簿データファ
イル、meibo.txt
を作成しよう。
サトウ ムネユキ SATOH Muneyuki さとう胸幸 青葉台 コウエキ タロウ KOEKI Taro 公益太郎 酒田 イイモリ ハナコ IIMORI Hanako 飯森花子 飯森山 サイトウ テツヤ SAITOH Tetsuya 斎藤徹夜 白夜の国
実際に検索してみよう。本来は漢字でパターンを指定したいところだが、漢
字を指定する前に覚えなければ行けないことが色々あって面倒なので、この実験
ではローマ字でパターンを指定しよう。Unixには正規表現を使ってファイルから
特定の行を検索してくれるものとして egrep
というコマンドが
ある。egrep
コマンドは
% egrep 正規表現パターン [ファイル群…]
のように起動し、0個以上の複数のファイルから「正規表現パターン」にマッ チする行だけを選んで出力してくれる。ファイルを0個指定すると、 標準入力から読み込んだデータから検索する。
標準入力/標準出力に関してはとても大事な概念なので Unixひとめぐりページを 良く読んでおくこと。
まずは検索してみよう。最初は、
どちらかを含む行を全部選んでみよう。この場合、大文字の I があっても無 くても良いので、正規表現パターンは "SAI?TOH" となる。
% egrep "SAI?TOH" meibo.txt
正規表現のパターンを ""
でくくっているのは、途中にある
?
記号をファイル名マッチだと思われないようにするためである。
このようにコマンドラインで正規表現パターンを指定するときは、パターンを
""
または ''
で必ず括ること。
実行結果は次のようになるだろう。
% egrep "SAI?TOH" meibo.txt
サトウ ムネユキ SATOH Muneyuki さとう胸幸 青葉台
サイトウ テツヤ SAITOH Tetsuya 斎藤徹夜 白夜の国
もう少し欲張って、楽になるように検索パターンを考えよう。
パターン指定にいちいち大文字を打つのは面倒だし、もしかしたらデータファイ
ルの方で Satoh と書いてしまう場合もあるので、大文字でも小文字でもどちら
でもマッチするようにしてみよう。検索のときに大文字小文字を区別しないため
には egrep
コマンドに -i
オプションを指定すれば
良い。
% egrep -i "sai?toh" meibo.txt
サトウ ムネユキ SATOH Muneyuki さとう胸幸 青葉台
サイトウ テツヤ SAITOH Tetsuya 斎藤徹夜 白夜の国
Rubyでは正規表現は / /
で括って指定する。たとえば、
直前の egrep
の例で指定した正規表現 "sai?toh"
はRubyでは、
/sai?toh/
と表記する。これに注意して、
指定したファイルから sai?toh というパターンを検索する
Rubyプログラム saito.rb
を作成すると次のようになる。
#!/usr/koeki/bin/ruby while line=gets if /sai?toh/i =~ line print line end end
まずは、実際に実行してみよう。egrep
コマンドと同様
検索したいファイルを引数として与えよう(検索パターンはRubyプログラム内に
記述してあるのでコマンドラインからは指定しなくて良い)。
% chmod +x saito.rb % ./saito.rb meibo.txt サトウ ムネユキ SATOH Muneyuki さとう胸幸 青葉台 サイトウ テツヤ SAITOH Tetsuya 斎藤徹夜 白夜の国
プログラム(本体部分)の内容を一行ずつ見ていこう。
while line=gets
gets
はこれまで使ったことのあるメソッドである。こ
れまでは、「キーボードから一行入力してその内容を文字列で返す」とい
う説明をしていたが、必ずしもキーボードから入力するとは限らない。
Rubyプログラム実行時に何かのファイルを引数として指定するとそのファ
イルの中味を順次読むようになる。Rubyプログラムに何も指定しないとキー
ボードから一行読むことになる。
今回の場合 ./saito.rb meibo.txt
と起動した。引数と
してmeibo.txt
を指定したので、gets
メソッ
ドは、meibo.txt
ファイルを1行ずつ読みこむ。つまり、一
回目の line=gets
で
line="サトウ ムネユキ SATOH Muneyuki さとう胸幸 青葉台\n"
となり、二回目の gets
で
line="コウエキ タロウ KOEKI Taro 公益太郎 酒田\n"
となる(\n
は改行コード)。4行あるので、
while line=gets
は4回くり返すことになる。
gets
はこれ以上読むデータが無くなると
false
を返し、while
ループは終了する。
if /sai?toh/i =~ line
このif
で、読みこんだ行が正規表現にマッチしているか
の判定を行なう。「正規表現にマッチしているか?」を意味する条件式は
正規表現 =~ 文字列
のように書く。/sai?toh/i
は、Rubyによる正規表現の
指定である。後の /
の直後にある i
は
「大文字小文字を区別しない」という意味を付加する働きを持つ。つまり、
egrep
コマンドの -i
オプションは、Rubyで
は、正規表現の直後に i
をつけることになる。
正規表現の後ろの =~
は、「正規表現がマッチすれば…」
という比較演算子である。逆に「マッチしなければ」を意味する演算子は
!~
であり、これも覚えておくと良い。。
=~
の右辺に指定した「文字列」が正規表現の比較対象
となる文字列である。
print line
line
変数にはデータファイルから読み込んだ行が入っ
ているので、それを出力する。もちろん、一つ上の行にif
があるので、正規表現にマッチした場合だけ該当行が出力される。
end
if
に対応するend
end
while
に対応するend