roy > naoya > 基礎プログラミングI·情報検索 > (8)正規表現[2] > 補足

(8) 06/09の授業内容:正規表現[2]補足

正規表現のパターンをキーボードから入力

正規表現のパターンは//でくくって示した。

/パターン/

前回の課題では特定のパターンにマッチする行を検索するために、毎回パターンを書き直して保存をし、ktermで実行をするという手順をとった。このようにプログラム中に直接パターンを記入する方法は、様々なパターンを試してみる場合には使い勝手が悪い。ここでは、キーボードから正規表現のパターンを入力し、そのパターンにマッチする行を表示するという方法について考えてみよう。このためには、もう1つの正規表現のパターンの指定方法を把握する必要がある。

reg= Regexp.new("[AB]C+")

これは[AB]C+を正規表現のパターンとし、このパターンをregという変数に代入するという表記方法である。実際にプログラムを作成して確認してみよう(reg.rb)。

#!/usr/koeki/bin/ruby

reg = Regexp.new("[AB]C+")
p reg

これを実行すると以下の通りとなる。

irsv{c10xxxx}% ruby reg.rb[Return]
/[AB]C+/

プログラムを実行するとpメソッドが変数regの中身を表示し、/[AB]C+/という結果を返す。

つまりRegexp.new("パターン")とすることで、()内は正規表現のパターンとなる。上記のプログラムでは("")内に[AB]C+という具体的なパターンを指定しているが、この部分は変数にすることができる。つまり、キーボードからパターンを入力して適当な変数に代入しておき、Regexp.new("")で("")内にその変数を指定すれば、キーボードから入力された正規表現のパターンで検索をすることが可能になる。この考えに基づき、前回のプログラムを変更してみよう。変更箇所を黄色で示す。

#!/usr/koeki/bin/ruby

STDERR.print"検索パターンは?:"
reg = STDIN.gets.chomp!
expression = Regexp.new(reg, true, "e")

while line=gets
  if expression =~ line
    print line
  end
end

続いてプログラムの変更点について解説する。

reg = STDIN.gets.chomp!

キーボードから入力された値を読み込み、改行を取り除いてregという変数に代入する。文字列のままでよいのでto_iをつけていない。この行ではgetsのまえにSTDINという見かけないものがついているが、これは標準入力という意味を持つ。前回のプログラムは実行する際に

irsv{c10xxxx}% ruby kensaku.rb meibo.txt[Return]

というように、検索対象となるファイルを指定した。そして、getsメソッドはファイル内を1行ずつ読み込むという作業を行っていた。今回のプログラムでは、検索をするデータは外部ファイルから読み込み、検索パターンはキーボードから読み込む。つまり、データを読み込む元が2種類あることになる。プログラムを実行する際にはgetsメソッドがどこからデータを読み込むのかを指定しないとコンピュータはどうすればよいかわからず困ってしまう(プログラムが意図したとおりに動かなくなるので、実際に困るのはコンピュータではなくプログラマ)。これを解決するために以下の方法が採用される。

複数の読み込み元がある場合の読み込み元の明示方法

  • データの読み込み元がキーボードのみ:gets
  • データの読み込み元がファイルのみで、ファイルはプログラム実行時に指定:gets
  • データの読み込み元がキーボードとファイルで、ファイルはプログラム実行時に指定:ファイルはgets、キーボードはSTDIN.gets

標準的には入力元はキーボードとなるため、ファイル、キーボードの双方からgetsメソッドで値を読み込む必要がある場合は、キーボードから読み込む場合に、標準入力であることを示すSTDINをつけSTDIN.getsと標記する。

この行の1つ上に、STDERR.print "検索パターンは?:"という行があり、ここでもSTDERRという見慣れないものがついている。これもSTDINの場合と考え方は同じで、printが""内を表示する先はディスプレイ以外にファイルを指定することができる。今回は指定したファイルの中身を読み込むだけであるが、来週は指定したファイルに結果を出力する方法についても学ぶ。出力先もディスプレイとファイルの2種類になるので、標準的な出力先であるディスプレイに表示する場合はprintではなく、STDERR.printを使用する。なお、今回のプログラムに限定すれば、ファイルに結果を書き出すようには書かれていないため、出力先はディスプレイのみとなる。このためSTDERRはなくてもよい。ただし、不要な場合につけていると間違いということではない。むしろディスプレイに表示することを明示的に示すことができるので、プログラムを書いた本人以外の人がプログラムを読む場合は、書き手の意図が伝わりやすい。

expression = Regexp.new(reg, true, "e")

先ほどは()の中に[AB]C+と直接入力していたが、ここではregという変数になっている。regには1つ上の行でキーボードから入力されたパターンが代入されている。reg以外にtrueや"e"と記載されているが、これらはそれぞれ下記の意味を持つ。

Regexp.newにおけるオプション

第2引数

  • true:大文字と小文字を区別してほしくない場合。/パターン/iと同じ意味。
  • false:大文字と小文字を区別してほしい場合。

第3引数(日本語の検索をしたいときに指定)

  • "e":EUCコードで書かれているものとして照合。/パターン/eと同じ意味。
  • "s":Shift-JISコードで書かれているものとして照合。/パターン/sと同じ意味。

101/102教室で英数字を検索する場合

  • Regexp.new(変数, true)
  • Regexp.new(変数, false)

101/102教室で日本語を検索する場合

  • Regexp.new(変数, true, "e")
  • Regexp.new(変数, false, "e")

if expression =~ line

前回のkensaku.rbではexpressionのかわりに/sai?to/iというように具体的なパターンが入力されていた。ここをexpressionという変数にすることで、キーボードから入力した任意のパターンに対するマッチングの有無を調べることができる。