Rubyプログラミング

Rubyプログラミング(2)


1.文字列の扱いに関連した話

Rubyのおもしろいところは、オブジェクト指向のスクリプト言語であることです。前回の例のプログラムではHello World!という文字列を扱いましたが、この文字列もStringというクラスのオブジェクトとして扱われています。

オブジェクト指向で考えるということは、データとそれを処理するメソッド(関数)から構成されることになります。オブジェクトに対しメソッドを使って情報を得ることができますが、.(ドット)でオブジェクトに対して用意されたメソッドを結びつけて考えます。

では、試してみましょう。まず、前回の例です。ファイル名はhello2.rbとして保存して試してみましょう。

print "Hello World!"

次にこの文字列に対し文字列の長さを返すメソッドlengthを結びつけて結果を見てみましょう。

print "Hello World!".length

実行してみると12という値が表示されます。次に変数に文字列を関係づけてから、この変数に対し同様の操作を行ってみます。関係付けるという言葉を使いましたが、文字列に対し変数の名前で利用できるようにするとでも考えてください。次の例では変数は英字小文字で始まっていますが、このような変数はローカル変数と呼ばれます。

a = "Hello.World!"
print a.length

このプログラムを実行してみると同じ結果が返ってきます。次にクラスStringのメソッドについていくつか試してみましょう。

a = "Hello World!"
a.each_byte{|x|
  printf "%c\n",x
}

このプログラムを実行すると縦に一文字ずつ"Hello World!"を構成する文字を表示します。each_byteというメソッドは各バイトに対してブロックを実行するということになっています。バイトとはここでは1文字分のデータということになります。ブロックとは{}で囲まれた部分で、プログラムなどを記述できます。つまり、"Hello World!"を構成する文字を左から順に{}に書かれたプログラムで処理するということになります。|x|というものがありますが、これはブロックパラメータと呼ばれるもので{}内で有効なパラメータということになっています。ブロックに関連するのはeach_byteというメソッドなので、これにより取り出された1文字分のデータがブロックパラメータに渡されます。

そして、printfを使ってxを画面に出力します。この時""で囲まれた部分で出力用の書式を指定しています。%cと書くことでxに入った1文字分のデータを文字に変換して画面に出力します。\nは改行の記号です。このように書式はCのprintfに近いものになっているようです。

さて、ここで日本語のデータを扱ってみましょう。プログラムは以下のようになります。

a = "こんにちは、さようなら"
a.each_byte{|x|
  printf "%c\n",x
}

これを実行すると日本語のデータは2バイトで表現するので、そのままデータが表示されることはありません。では、現状ではどのようなコードが使われているか調べてみましょう。次のコードを試してみましょう。プログラムの先頭にある#はその行がコメントであることを示し、プログラムとして解釈されません。

print $KCODE
#a = "こんにちは、さようなら"
#a.each_byte{|x|
#  printf "%c\n",x
#}

$KCODEの内容を表示します。NONEと表示されたことと思います。これは日本語対応になっていないことになります。日本語のコードに対応するものとして、SJIS、EUC、UTF-8の三つが用意されています。WindowsではSJISを使いますので、これで設定して文字列の長さを調べてみましょう。ただし日本語の文字の長さを調べるメソッドはjlengthで、jcodeライブラリが必要になります。

require "jcode"
$KCODE = "SJIS"
a = "こんにちは、さようなら"
print a.jlength
#a.each_byte{|x|
#  printf "%c\n",x
#}

ちょっと、長くなりましたが正確に文字列の長さを返すようになりました。次に文字列から日本語の文字を1個ずつ取り出してみましょう。まず、次の例で再挑戦してみましょう。

$KCODE = "SJIS"
a = "こんにちは、さようなら"
a.each_byte{|x|
  printf "%c\n",x
}

これだと、1文字といっても1バイト単位に取り出しているのでこのままでは使えません。工夫すればなんとかなるかもしれませんが、それよりは別の書き方を見つけた方が得策です。

Rubyではsplitというメソッドがあります。日本語の問題から離れてしばらくこれを使って練習してみましょう。まず、基本的な使い方からです。/と/の間には空白が一つ入ります。

a = "Hello World!"
print a.split(/ /)

実行してみるとHelloとWorld!の間の空白がとれて単語がつながっています。これはsplitで区切り文字を指定して、区切られた単語を画面に出力しているからです。メソッドsplitで区切り文字を指定しますが//に空白を1個入れて指定します。//は正規表現と呼ばれるパターンマッチ用の表現を書くために使用されています。

こうやってsplitされたものは配列や変数に分けて格納することができます。次の例を試してみましょう。

a = "Hello World!"
b,c = a.split(/ /)
print b,"\n"
print c

この例では多重代入という方法を使いsplitしたものを一度に二つの変数bとcに代入しています。次の例を試してみましょう。

a = "Hello World!"
d = a.split(/ /)
print d

この例を試すと二つの単語がつながって画面に出力されます。変数dにはどうも配列としてデータが格納されたようです。ここで配列の例を試してみます。次の例を試してください。

a = "Hello World!"
e = ["Hello", "World!"]
d = a.split(/ /)
print d,"\n"
print e

同じような結果が表示されます。配列は[]で囲んで作ります。例では変数eに作った配列を割り当てています。変数eを出力すると配列の内容が出力されます。配列の要素は左から順に0、1のように番号が割り振られます。次の例を試してみましょう。

a = "Hello World!"
e = ["Hello", "World!"]
d = a.split(/ /)
print d,"\n"
print e[0],"\n"
print e[1],"\n"

このようにすれば配列の要素を表示できそうです。ではsplitで分けたものも同様に扱えそうです。次の例を試してみましょう。

a = "Hello World!"
e = ["Hello", "World!"]
d = a.split(/ /)
print d[0],"\n"
print d[1],"\n"
print e[0],"\n"
print e[1],"\n"

これで、splitを使って分けたものも配列として扱われているようです。配列から要素を取り出すにはループを使えばよさそうですが、簡単に表現できる方法がRubyには用意されています。まず次の例を試してみましょう。

a = "Hello World!"
e = ["Hello", "World!"]
d = a.split(/ /)
d.each do |x|
  print x,"\n"
end

配列が割り当てられている変数dに対してメソッドeachを使用しています。次にブロックとしてdoとendでプログラムを囲んでいます。これは前に練習したように次のように書くこともできます。

a = "Hello World!"
e = ["Hello", "World!"]
d = a.split(/ /)
d.each{|x|
  print x,"\n"
}

そして、変数dは省略して次のように書くこともできます。

a = "Hello World!"
e = ["Hello", "World!"]
a.split(/ /).each{|x|
  print x,"\n"
}

練習1.では、配列eから要素を取り出すようにしてください。

a = "Hello World!"
e = ["Hello", "World!"]
a.split(/ /).each{|x|
  print x,"\n"
}
e.each{|x|
  print x,"\n"
}

上記のプログラムのようになります。

さて、このメソッドsplitの正規表現を表現する//に空白を与えず/を二つ続けて並べただけでプログラムを試してみましょう。変数eに関する部分は除いてあります。

a = "Hello World!"
a.split(//).each{|x|
  print x,"\n"
}

このようにすると縦に一文字ずつ出力するようになります。//のように区切り文字を入れない場合、一文字ずつ区切って出力するようになっているようです。

さて、なんとなく日本語が扱えそうになってきました。データに日本語を与えて試してみましょう。

a = "こんにちは、さようなら"
a.split(//).each{|x|
  print x,"\n"
}

ですが、やはり表示されません。コードの指定をしてみましょう。

$KCODE = "SJIS"
a = "こんにちは、さようなら"
a.split(//).each{|x|
  print x,"\n"
}

やっと日本語の文字を一文字ずつ取り出すことができるようになりました。ここではメソッドsplitを使用しましたが、メソッドscanを使って似たような操作を行うことができます。

さて、このようにRubyを含めたスクリプト言語は文字列を簡単なコードでいろいろ操作することができます。

<参考>参考書はいろいろありますが、私がよく使っているものを4冊あげておきます。

・オブジェクト指向スクリプト言語Ruby、まつもとゆきひろ、石塚圭樹 共著、アスキー出版局、2000、4000円

基本から応用まで幅広い話題を取り上げています。例にも実際に使えそうなものが散りばめてあります。

・Rubyデスクトップリファレンス、まつもとゆきひろ著、オライリージャパン、2000、1000円

英語版も準備されているのかな。ライブラリ別にメソッドを調べるような時に便利です。リファレンス用なので、ある程度Rubyについて勉強しておく必要があります。

・Rubyレシピブック、青木峰郎+後藤裕蔵+高橋征義 著、まつもとゆきひろ監修、ソフトバンクパブリッシング、2004、2800円

クックブックと呼ばれるタイプの本でテクニックを項目別にまとめた本です。

・Rubyプログラミング入門、原信一郎 著、まつもとゆきひろ監修、オーム社開発局、2000、2800円

Rubyの概略から入って、各論に入り詳しい説明を行っています。自分の探したい項目を見つけるには一通り目を通す必要があります。