#+OPTIONS: ^:{}
#+TITLE: はじめてのRuby
#+AUTHOR: Shun Takahashi
#+LANGUAGE: jp
#+OPTIONS: H:4 toc:t num:2
# -*- mode: org; -*-
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
#+HTML_HEAD:
# +SETUPFILE: /Users/bob/Github/org-html-themes/setup/theme-readtheorg-local-daddygongon.setup
+ 各実行方法(irb, file起動)の違いについて言及している,レジメ(report)にする.自分の独自のまとめをかく....
+ formatを調整する.c-c c-e hoでhtmlに打ち出す.
# 本記述内のプログラムのサンプルはsample_progフォルダに記載
# 13:00 2018/7/21 -
* はじめてのRuby
** イントロダクション
それではRubyを使ってみましょう。
この章では次の内容について紹介します。Rubyを使ったプログラミングの概要をつかんでください。
+ Rubyを使う- Rubyを使って、プログラムを実行してみます。
+ 文字や数値を使う- 文字や数値を出力したり、計算を行ったり、変数に代入したりします。
+ 条件判断や繰り返しを行う- 数値や文字列を比較して条件判断や、処理の繰り返しを行います。
# 冒頭に今回の章で学ぶ内容の概要を示しているため、何が身につくのかわかりやすい
** Rubyの実行方法
*** イントロダクション
まずは、画面に文字を表示するプログラムを作り、実行してみましょう。
Rubyで書かれたプログラムを実行する方法はいくつかあります。いちばん一般的なのは、rubyというコマンドを使って実行する方法です。次によく使うのが、irbというコマンドを使って対話的に実行する方法です。小さいRubyプログラムの時は、irbコマンドを使う方が簡単に実行できます。
ここではまずrubyコマンドを使う方法を紹介して、その後でirbコマンドを使う方法も紹介します。
なお、Rubyそのものをインストールしていない人は、「付録A Ruby実行環境の準備」を見て、あらかじめインストールしておいてください。
+ 付録Aについては割愛
+ 注 本書で使用するRubyのバージョンは、Ruby2.3です。Mac OS XやLinuxを使用している場合、標準でインストールされているRubyのバージョンが古いことがあります。その場合、新しいRubyをインストールしてください。
# 動作環境についての注釈
*** rubyコマンドを使う方法
では、はじめて実行するプログラムList1.1を見てみましょう。
List1.1 helloruby.rb
#+begin_src ruby
print('Hello, Ruby.\n')
#+end_src
# begin_srcからend_srcの間の記述はRubyで動作するプログラム
*注 「\」(バックスラッシュ)は、Windowsでは「¥」(円記号)と表示されます。本書の中では、原則として「\」に統一します。
……ちょっと拍子抜けしたでしょうか?「プログラム」と聞いて、何かすごく長い暗号めいたものを想像されたかもしれませんが、このプログラムはたったの1行です。文字数にしても20字ちょっとしかありません。でも、これも立派なプログラムですし、実行すればちゃんと目的を果たします。
このプログラムをエディタで入力し、ファイル名を「helloruby.rb」にして、ファイルとして保存してください。ファイル名の「.rb」は、Rubyのプログラムであることを表しています。
*メモ プログラムを入力するには、「エディタ」または「IDE」というソフトウェアを使います。エディタやIDEについては、「A.5 エディタとIDE」をご覧ください
# A.5は割愛
それでは、このプログラムを実行してみましょう。コンソールを起動します。
*メモ コンソールの起動方法については、「付録A Ruby実行環境の準備」でOS別に説明しています。
コンソールを起動したら、ファイルhelloruby.rbを置いたフォルダに、cdコマンドで移動します。たとえばWindowsを使っていて、Cドライブのsrcフォルダ(c:\src)にファイルを置いたのであれば、次のように入力します。
# 以降、特に言及のない場合は「>」で始まるコマンドはコンソール上の操作とする
> cd c:\src
そこで、
> ruby helloruby.rb
と入力します。すると、例1.1のように、「Hello, Ruby.」と表示されます。
例1.1 rubyの起動
shun@MAC-no-MacBook-Air ~/g/m/t/r/sample_prog> ruby helloruby.rb
Hello, Ruby.
shun@MAC-no-MacBook-Air ~/g/m/t/r/sample_prog>
*メモ もしエラーが出てしまうようなら、第10章のコラム「エラーメッセージ」および「付録A Ruby実行環境の準備」を確認してください。
# 割愛
*** 1.1.2. irbコマンドを使う方法
irbコマンドを使う方法も紹介します。
irbコマンドは、rubyコマンドと同様にコンソールから実行します。ただし、プログラムを書いたファイルは指定しません。
irbコマンドを実行すると、次のように入力プロンプトが表示されます
shun@MAC-no-MacBook-Air ~/g/m/t/r/sample_prog> irb
irb(main):001:0>
ここで、先ほどのプログラムList1.1をそのまま入力し、[Enter]キーを押すと、その場で実行されます。
irb(main):001:0> print("Hello, Ruby.\n")
Hello, Ruby.
=> nil
irb(main):002:0>
# 2行目「Hello, Ruby.」が1行目のprintメソッドによって表示された文字列
*メモ 3行目に表示される「=>nil」というのが、print文自体の戻り値です。詳しくは「7.3.1 メソッドの戻り値」で説明します。
このように、入力したプログラムをその場で実行できるので、簡単なテストにはとても便利です。ただし、大きなプログラムを試すのには不向きなので、そのような場合にはrubyコマンドを使いましょう。
irbコマンドを終了するに「exit」と入力して[Enter]キーを押すか、[Control]([Ctrl])キーを押しながら[d]キーを押します。
# irbコマンドは数行程度のごく簡単なプログラムを.rbプログラムで記述せずに直接打ち込み、その動作を確認できるコマンド。単純な動作確認の際に有用?
*注 Mac OS XやWindowsを使っている場合、irbコマンドでは日本語が正しく入力できないことがあります。その場合、irbコマンドに--noreadlineオプションをつけて「irb --noreadline」と実行してください。これでreadline機能がオフになり、日本語を正しく入力できるようになります。ただし、readline機能をオフにすると、入力済みの文字の編集機能やヒストリ入力支援機能などが使えなくなってしまうので注意してください。
# irbコマンドに限らず、コンソール上で動作するほとんどのコマンドには、設定を変更できるオプションが存在する。オプションは一般的にコマンドの後に「-」や「--」と何らかの文字や文字列を記述することで動作する。
** プログラムの解説
*** イントロダクション
それでは、ほんの1行だけではありますが、List1.1のプログラムを解説しましょう。
*** 1.2.1. オブジェクト
#+begin_src ruby
print("Hello, Ruby.\n")
#+end_src
まず、「"Hello, Ruby.\n"」という部分に注目します。
これをStringオブジェクト、または文字列オブジェクト、あるいは単に文字列と呼びます。「Hello,Ruby.」という文字列を意味するオブジェクト、というわけです。
Rubyでは、文字列、数値、時刻など様々なデータがオブジェクトになります。
# rubyはオブジェクト指向言語である
*メモ 文字列の終わりの「\n」は改行を表す文字です。
*** 1.2.2. メソッド
#+begin_src ruby
print("Hello, Ruby.\n")
#+end_src
今度はprintという部分に注目しましょう。
「print」は、メソッドです。メソッドとは、オブジェクトを扱うための手続きのことです。「数値」を使って足し算や掛け算をしたり、「文字列」同士をつなげたり、「ある時刻」の1時間後や1日後を求めたりといったことは、すべてメソッドを起動することによって行われます。
printメソッドは、「()」のなかの内容をコンソールに出力するメソッドです。ですから、helloruby.rbでは、「Hello, Ruby.」という文字列オブジェクトが表示されています。
メソッドに渡す情報のことを引数といいます。例えば、printメソッドの機能を説明する場合には「printメソッドは引数として与えられた文字列をコンソールに出力します」といった使い方をします。
printメソッドの引数を書き換えて、別の文字列を表示するプログラムにしてみましょう。
helloruby_2.rb
#+begin_src ruby
print("Hello, RUBY!.\n")
#+end_src
今度は大文字で「Hello,RUBY!」と表示するようになります。ちょっと元気の良いあいさつになりましたか?
** 文字列
*** イントロダクション
文字列について、もう少し詳しくもう少し見ていくことにしましょう。
*** 1.3.1. 改行文字と「\」
先ほど、文字列の「\n」は改行を表すと説明しました。普通の文字を使って改行を書けるおかげで、たとえば
Hello,
Ruby
!
と表示させるには、
#+begin_src ruby
print("Hello, \nRuby\n!\n")
#+end_src
と書くことができます。もっとも、
#+begin_src ruby
print("Hello,
Ruby
!
")
#+end_src
などと書いても、同じように表示されます。しかし、この書き方だとプログラムが読みにくくなってしまうので、あまり良い書き方ではありません。せっかく改行を表す書き方があるのですから、それを使う方が良いでしょう。
「\n」以外にも、文字列の中で特殊な文字を埋め込みたいときに「\」を使います。たとえば、「"」は文字列の始まりと終わりを表す文字ですが、これを文字列の中に含める場合には「\"」とします。
helloruby_3.rb
#+begin_src ruby
print("Hello, \"Ruby\".\n")
#+end_src
上記のプログラムは、
Hello, "Ruby".
と表示されます。
このように、文字列中の「\」はそれに続く文字に特別な意味を与える文字になっています。そのため、「\」そのものを文字列中に含めたい時には、「\\」とかく必要があります。たとえば
#+begin_src ruby
print("Hello \\ Ruby!\n")
#+end_src
上記のプログラムは、
Hello \ Ruby!
と表示されます。2つあった「\」が1つになっていることに注意してください。
# 記載されているプログラムについて、同じような作業を繰り返すと判断した場合、sample_progには記載しないこととする
*** 1.3.2. 「''」と「""」
文字列オブジェクトを作るための区切り文字には、「" "」(ダブルクォート)ではなく、「' '」(シングルクォート)を使うこともできます。先ほどのプログラムを
helloruby_4.rb
#+begin_src ruby
print('Hello,\nRuby\n!\n')
#+end_src
とシングルクォートに書き換えて実行してみましょう。すると今度は
Hello,\nRuby\n!\n
というように、「' '」の中の文字がそのまま表示されます。
このように「' '」で囲った文字列は、「\n」などの特殊文字の解釈を行わず、そのまま表示します。ただし例外として、「\」と「'」を、文字列中に文字そのものとして含めたいときのみ、その文字の前に「\」をつけます。こんな感じです。
helloruby_5.rb
#+begin_src ruby
print('Hello, \\ \'Ruby\'.')
#+end_src
実行すると次のように表示されます。
Hello, \ 'Ruby'.
# 「" "」と「' '」の違いは特殊な文字を表示する場合の記述の違いのみ。
# 2者間の違いを説明する場合に実例をまじえて説明すると違いがわかりやすい。
** メソッドの呼び出し
メソッドについてもう少し説明しましょう。
Rubyのメソッドでは「()」を省略することができます。そのため、先ほどのプログラム(List1.1)でのprintメソッドは、
helloruby_6.rb
#+begin_src ruby
print "Hello, Ruby.\n"
#+end_src
と書くこともできます。
また、いくつかの文字列を続けて表示したい時には、「,」で区切れば、並べた順に表示できます。ですから
#+begin_src ruby
print "Hello, ", "Ruby", ".", \n"
#+end_src
なんて書き方もできるわけですね。これは、表示したいものがいくつもある時に使うと便利です。とはいえ、要素が複雑に込み入ってくると、「()」をつけたほうがわかりやすくなります。慣れるまではこまめに「()」を書いておきましょう。本書では、単純な場合には「()」を書いて表記しています。
さらに、メソッドを順に並べて書くと、その順にメソッドを実行します。例えば
helloruby_7.rb
#+begin_src ruby
print "Hello, "
print "Ruby"
print "."
print "\n"
#+end_src
などと書いても、同じように「Hello,Ruby.」と表示するプログラムになります。
** putsメソッド
printメソッド以外にも文字列を表示するメソッドがあります。putsメソッドは、printメソッドとは異なり、表示する文字列の最後で必ず改行します。これを使えば、List1.1は
helloruby_8.rb
#+begin_src ruby
puts "Hello, Ruby."
#+end_src
と書けるようになります。ただし、
#+begin_src ruby
puts "Hello, ", "Ruby!"
#+end_src
のように2つの文字列を渡した場合には、
Hello,
Ruby!
と、それぞれの文字列の末尾に改行が追加されます。printメソッドとは少し使い勝手が違いますね。この2つのメソッドは、場面に応じて使い分けてください。
** pメソッド
さらにもう1つ、表示のためのメソッドを紹介しましょう。オブジェクトの内容を表示する時に便利な「p」というメソッドです。
たとえば、数値の100と文字列の”"100"を、printメソッドやputsメソッドで表示させると、どちらも単に「100」と表示されてしまいます。これでは本当はどちらのオブジェクトなのか、表示結果から確認できません。そんな時には、pメソッドを使うのが便利です。pメソッドなら、文字列と数値を違った形で表示してくれるのです。さっそく試してみましょう。
puts "100" #=> 100
puts 100 #=> 100
p "100" #=> "100"
p 100 #=> 100
*メモ 本書では、プログラム中で出力した内容を表すために、出力用のメソッドの横に「#=>」という文字を置き、その右側に出力された文字を並べて書くという表記を用いています。この例では、「puts "100"」や「puts 100」、「p 100」というメソッドでは、「100」という文字列が出力され、「p "100"」というメソッドでは「"100"」という文字列が出力される、という意味になります。
# メモや注釈だけを折りたたみたい
このように、文字列を出力する場合、「" "」で囲んで表示してくれるわけです。これなら一目瞭然ですね。さらに、文字列の中に含まれる改行やタブなどの特殊な文字も、「\n」や「\t」のように表示されます(List1.2)。
List1.2 puts_and_p.rb
#+begin_src ruby
puts "Hello,\n\tRuby."
p "Hello,\n\tRuby."
#+end_src
実行例は以下のようになります。
> ruby puts_and_p.rb
Hello,
Ruby.
"Hello,\n\tRuby."
printメソッドは実行結果やメッセージなどを普通に表示したい時、pメソッドは実行中のプログラムの様子を確認したい時、と使い分ければ良いでしょう。原則として、pメソッドはプログラムを書いている人のためのメソッドなのです。
# ここまで、print,puts,p の3つのメソッドの違い、使い分け方について個別に言及している
# - 16:15 2018/7/21
** 日本語の表示
# 13:00 2018/7/22 -
ここまで、文字列にはアルファベット(英字)を使ってきました。
今度は日本語を表示してみましょう。日本語の表示も難しい事は何もありません。単にアルファベットの代わりに日本語を「" "」の中に書くだけです。こんな感じになります。
List1.3 kiritsubo.rb
#+begin_src ruby
print "いづれの御時にか女御更衣あまたさぶらいたまいけるなかに\n"
print "いとなむごとなき際にはあらぬがすぐれて時めきたまふありけり\n"
#+end_src
ただし、文字コードの設定によっては、エラーが出たり、正しく表示されない場合があります。その場合、コラム「日本語を扱う場合の注意」を参照してください。
*** コラム「日本語を扱う場合の注意」
環境によっては、日本語を含むスクリプトを実行すると次のようなエラーになります。
実行例
> ruby kiritsubo.rb
kiritsubo.rb:1: invalid multibyte char (UTF-8)
kiritsubo.rb:1: invalid multibyte char (UTF-8)
これはソースコードの文字コード(エンコーディング)が指定されていないからです。Rubyでは「# encoding: 文字コード」というコメントを1行目に記述することによってソースコードの文字コードを指定します(文字コードを決めるルールのことをエンコーディングと言います)。このコメントをマジックコメントと言います。
Windowsで一般的に使われているエンコーディングShift_JISでソースコードを記述した場合は、次のようにマジックコメントを書きます。
#+begin_src ruby
# encoding: Shift_JIS
print "いづれの御時にか女御更衣あまたさぶらいたまいけるなかに\n"
print "いとなむごとなき際にはあらぬがすぐれて時めきたまふありけり\n"
#+end_src
このようにコメントで文字コードを指定することによって、Rubyがソースコード中の日本語を正しく認識できるようになります。次の表にプラットフォームごとによく使われる文字コードをまとめています。複数の文字コード名が挙げられている場合は、環境に合わせて適切なものを選んでください。
なお、マジックコメントがないソースコードの文字コードはUTF-8と仮定されます。そのため、UTF-8のソースコードを使う場合はマジックコメントは不要です。
これ以外でも、前述のpメソッドで日本語の文字列を出力すると、いわゆる「文字化け」をしたような出力になる場合があります。そのような場合が、出力用の文字コードを指定するために「-E 文字コード」の形式でコマンドラインオプションを指定してください。コンソールがUTF-8を受け付ける場合は次のようにします。
実行例
> ruby -E UTF-8 スクリプトファイル名
> irb -E UTF-8
** 数値の表示と計算
*** イントロダクション
文字列に続いて、今度は「数値」を扱ってみましょう。Rubyのプログラムでは、整数や少数(浮動小数点数)を、自然な形で扱うことができます。
*** 1.8.1. 数値の表示
まずは文字列の代わりに数値を表示するところから始めてみます。「1.2 プログラムの解説」で、「Rubyでは文字列は文字列オブジェクトという形になっている」と説明しました。同じように、数値も「数値オブジェクト」として扱われます。
Rubyで整数オブジェクトを表現するのは簡単です。そのまま数字を書けば良いだけです。たとえば
1
と書けば「1」の値の整数(Fixnum)オブジェクトになります。また、
100
と書けば、「100」の値の整数オブジェクトになります。
さらに、
3.1415
などと書けば、「3.1415」の値の浮動小数点数(Float)オブジェクトになります。
*メモ 「Fixnum」や「Float」というのは、それぞれのオブジェクトが所属する「クラス」の名前です。クラスについては、第4章と第8章で説明します。
数値を表示するには、文字列と同様にprintメソッドやputsメソッドを使います。
puts(10)
というメソッドを実行すると、
10
と画面に表示されます。
*** 1.8.2. 四則演算
数の計算を行ったり、その結果を表示したりすることもできます。四則演算をやってみましょう。
ここではirbコマンドを使ってみます。
実行例
> irb --simple-prompt
>> 1 + 1
=> 2
>> 2 - 3
=> -1
>> 5 * 10
=> 50
>> 100 / 4
=> 25
*メモ irbコマンドの後の--simple-promptは、irbのプロンプト表示を簡易にするためのオプションです。
プログラミング言語の世界では、掛け算の記号に「*」(アスタリスク)を、割り算の記号に「/」(スラッシュ)を使うのが一般的です。Rubyもこの習慣にならっています。
もう少し四則演算をやってみましょう。普通の計算では、「足し算・引き算」と「掛け算・割り算」には計算の順序が決められていますが、Rubyでも同じです。つまり、
20 + 8 / 2
とすれば答えは「24」になります。「20 + 8」を2で割りたいときは、「()」で囲って、
(20 + 8) / 2
とします。答えは「14」になります。
*** 1.8.3. 数学的な関数
四則演算以外にも、平方根や、三角関数の「sin」「cos」、指数関数などの数学的な関数が利用できます。ただし、その場合、関数の前に「Math.」という文字列をつける必要があります。
*メモ 「Math.」をつけずに「sin」「cos」などの関数を使うには、「include Math」という文が必要です。これについては「8.7.2 名前空間の提供」で説明します。
sinはsinメソッド、平方根はsqrtメソッドで求めます。メソッドを実行すると、計算した結果を得ることができます。このことを「メソッドが値を返す」といい、得られる値のことを戻り値といいます。
# sqrt -> square root
実行例
> irb --simple-prompt
>> Math.sin(3.1415)
=> 9.265358966049024e-05
>> Math.sqrt(10000)
=> 100.0
*注 Rubyのバージョンや実行する環境により、結果の桁数などが異なる場合があります。
1番目のsinの答えである「9.265358966049024e-05」ですが、これは、極端に大きい数や、極端に小さい数を表す時に使われる表記方法です。「(小数)0(整数)」と表示された時は、「(小数)*(10の(整数)乗)」の値、と解釈してください。この例の場合、「9.265358966049024×10の−5」ということになるの、つまりは0.00009265358966049024という値を表しています。
** 変数
プログラミングに欠かせない要素として変数があります。変数とは、「もの」につける名札のようなものです。
オブジェクトに名札をつけるには、
変数名 = オブジェクト
と書きます。このことを「変数にオブジェクトを代入するといいます。
例
alphabet = "abcdefg"
num = 10
age = 18
name = "TAKAHASHI"
変数の利用例として、直方体の表面積と体積を求めるプログラム(List1.4)を見てみましょう。
List1.4 area_volume.rb
#+begin_src ruby
x = 10
y = 20
z = 30
area = (x*y + y*z + z*x) * 2
volume = x * y * z
print "表面積=", area, "\n"
print "体積=", volume, "\n"
#+end_src
変数をまったく使わなければ、
#+begin_src ruby
print "表面積=", (10+20 + 20*30 + 30*10) * 2, "\n"
print "体積=", 10*20*30, "\n"
#+end_src
といったプログラムになってしまいます。これでは値を1つ変更するために何箇所も修正しなければいけません。この例はたったの2行なので大したことはありませんが、ちょっと大きなプログラムになると、そのような変更をきちんと行うのは大変な手間となります。また、変数には、あたいが何をしているのかを明確にするという意味もあります。したがって、わかりやすい名前をつけることが大切です。例えば、
#+begin_src ruby
hoge = (foo*bar + bar*baz + baz*foo) * 2
huni = foo * bar * baz
#+end_src
という調子では、何をやっているのかさっぱりわからないプログラムになってしまいます。変数名には、「area」や「volume」など、そのままで意味のわかる単語などを使うように、普段から心がけましょう。
*** 1.9.1. printメソッドと変数
printメソッドの動きをもう少し見てみましょう。
print "表面積=", area, "\n"
このprintメソッドの呼び出しには「"表面積="」「area」「"\n"」の3つの引数を指定しています。printメソッドはこれらの引数の値を順番に出力します。
「"表面積="」は「表面=」という値を持った文字列なので、それがそのまま出力されます。「area」はareaという変数に関連づけられたオブジェクトになります。この例では2200という整数になっているので、printメソッドはその値を出力します。
最後の「"\n"」は改行を表す文字列なので、そのまま出力します。
これらの3つの値をprintメソッドで処理した結果として「表面積=2200」と改行が画面に表示されるというわけです。
printメソッドに渡す文字列は次のように書くこともできます。
print "表面積=#{area}\n"
「"表面積=#{area}\n"」が全体で1つの文字列になっています。「#{area}」は文字列の中に変数areaの値を埋め込むという書き方です。文字列の中に「#{変数名}」と書くと、文字列にデータを埋め込むことができます。計算結果の変数名を埋め込む代わりに、「"表面積=#{(x*y + y*z + z*x) * 2}\n"」のように計算式を直接描いても同じ結果を得られます。
画面に結果を出力する場合は改行も出力することが多いため、putsメソッドを使って次のように書けば、「\n」も必要なくなり、プログラムがスッキリします。
puts "表面積=#{area}"
# - 14:23 2018/7/22 -
** コメントを書く
プログラムの中には、コメントを書くことができます。コメントは、プログラム中にp書かれていても、直接プログラムとしては扱われません。つまり、プログラムの実行には何の関係もないもの、ということです。「どうしてプログラムの中に、実行とは関係のない余計なものを書くのだろう?」と思われるかもしれません。確かに一度書いて実行すればそれっきり、というプログラムであれば、コメントは特に必要ないでしょう。しかし、一度書いたプログラムを何度も使いまわすことも少なくありません。そのような時に、
・プログラムの名前や作者、配布条件などの情報
・プログラムの説明
などを書いておくために、コメントが使われます。
コメントを表す記号は「#」です。行頭に「#」があれば、1行まるまるコメントになります。行の途中に「#」があれば、「#」の部分から行末までがすべてコメントになります。また、行頭から始まる「=begin」と「=end」で囲まれた部分もコメントになります。これは、プログラムの先頭や最後で、長い説明を記しておくのに重宝します。
List1.5は、先ほどのList1.4にコメントを追加したプログラムです。
List1.5 comment_sample.rb
#+begin_src ruby
=begin
「たのしいRuby 第5版」サンプル
コメントの使い方の例
2006/06/16 作成
2006/07/01 一部コメントを追加
2015/10/01 第5版に更新
=end
x = 10 # 横
y = 20 # 縦
z = 30 # 高さ
# 表面積と体積を計算する
area = (x*y + y*z + z*x) * 2
volume = x * y * z
# 出力する
print "表面積=", area, "\n"
print "体積=", volume, "\n"
#+end_src
# このコメントを含め、赤字で表示される箇所はコメントになっている
なお、コメントは、先ほど挙げた目的以外にも、「この行の処理を一時的に実行させないようにする」といったことにも使います。
C言語のコメントのように、行の途中だけをコメントにするような書き方はありません。行末まで必ずコメントになります。
# なぜ実装されていない?
** 制御構造
*** イントロダクション
プログラミング言語には、制御構造というものがあります。
これは、何かの条件によって、プログラムの実行順序を変えたり、プログラムの一部を実行させなかったりするための仕掛けです。
*** 1.11.1. 制御構造の分類
制御構造を大雑把に分類すると次のようになります。
・逐次処理:プログラムを書かれた通りに、先頭から順に実行する。
・条件判断:ある条件が成り立つ場合は〇〇を、そうでない場合は××を実行する
・繰り返し:ある条件が成り立つ間、〇〇を繰り返し実行する
・例外処理:何か例外が発生した場合には、〇〇を実行する
逐次処理というのは、通常の処理のことです。特に何も指定していない場合、プログラムは書かれた順に実行されます。
条件判断は、条件に応じて処理が分岐します。条件が満たされない場合、書かれた処理の一部を飛ばして、実行が行われます。Rubyでは、if文やunless文、case文などが条件判断文になります。
繰り返しは、条件に応じて、ある処理を何度も繰り返して実行することです。この場合、書かれた順序に逆らって、すでに一度実行されているところに戻って、再度実行が行われます。
例外処理はやや特殊です。想定していない問題が発生した時、それまで実行していた部分を抜け出して、別の場所から実行を再開する処理です。場合によっては、そこでプログラムが終了してしまうこともあります。
ここでは「条件判断」と「繰り返し」を取り上げます。
** 条件判断:if ~ then ~ end
ある条件によって挙動が変わるプログラムを作るには、if文を使います。if文の構文は、次のようになります。
if 条件 then
条件が成り立った時に実行したい処理
end
条件には、値がtrueまたはfalseとなる式を書くのが一般的です。2つの値を比較して、一致すればtrue、一致しなければfalse、などが条件にあたります。
数値の場合、例えば大小関係の比較には、等号や不等号を使います。Rubyでは、「=」は代入のための記号として使われるので、一致するかどうか調べるには「=」を2つ並べた記号「==」を使います。また、「≦」と「≧」には、「<=」と「>=」を使います。
このような比較の結果はtrueまたはfalseとなります。もちろん、trueはその条件が成り立っている場合、falseは成り立っていない場合です。
p (2 == 2) #=> true
p (1 == 2) #=> false
p (3 > 1) #=> true
p (3 > 3) #=> false
p (3 >= 3) #=> true
p (3 < 1) #=> false
p (3 < 3) #=> false
p (3 <= 3) #=> true
文字列の比較もできます。この場合も「==」を使います。同じ文字列ならtrue、異なる文字列ならfalseを返します。
p ("Ruby" == "Ruby") #=>true
p ("Ruby" == "Rubens") #=>false
値が異なっていることを判断するには、「!=」を使います。これは「≠」の意味ですね。
p ("Ruby" != "Rubens") #=> true
p (1 != 1) #=> false
では、これらを使って、条件判断文を書いてみましょう。変数aの値が10以上の場合は「greater」、9以下の場合は「smaller」と表示するプログラムはList1.6のようになります。
List1.6 greater_smaller.rb
#+begin_src ruby
a = 20
if a >= 10 then
print "greater\n"
end
if a <= 9 then
print "smaller\n"
end
#+end_src
thenは省略することもできます。その場合、if文は次のようになります。
if a >= 10
print "greater\n"
end
また、条件に一致するときとしないときで違う動作をさせたい場合は、else文を使います。次のような構文になります。
if 条件 then
条件が成り立った時に実行したい処理
else
条件が成り立たなかった時に実行したい処理
end
これを使って、List1.6を書き直すと、List1.7のようになります。
List1.7 greater_smaller_else.rb
#+begin_src ruby
a = 20
if a >= 10
print "greater\n"
else
print "smaller\n"
end
#+end_src
** 繰り返し
*** イントロダクション
同じこと、または同じようなことを何度か繰り返したい場合があります。繰り返し処理を行う方法を2つ紹介しましょう。
*** while文
while文は、繰り返しを行うための基本的な構文です。なお、doは省略することもできます。
while 繰り返し続ける条件 do
繰り返したい処理
end
例:1から10までの数を順番に表示する
#+begin_src ruby
i = 1
while i <= 10
print i, "\n"
i = i + 1
end
#+end_src
*** timesメソッド
繰り返しの回数が決まっているときは、「times」というメソッドを使うとシンプルにできます。なお、こちらの「do」は省略できません。
繰り返す回数.times do
繰り返したい処理
end
例:「All work and no play makes Jack a dull boy.」と100行表示する
#+begin_src ruby
100.times do
print "All work and no play makes Jack a dull boy.\n"
end
#+end_src
timesメソッドはイテレータと呼ばれるメソッドです。イテレータ(iterator)は、Rubyの特徴的な機能です。スペルからもわかるように「繰り返す(iterate)もの(-or)」という意味です。オペレータ(operator)が「演算(operate)するもの」として「演算子」と呼ばれるのを真似るなら、さしずめ「繰り返し子」「反復子」というところでしょうか。その名の通り、繰り返しを行うためのメソッドです。
Rubyはtimesメソッド以外にも数多くのイテレータを提供しています。イテレータの代表はeachメソッドです。eachメソッドについては、第2章で配列やハッシュと一緒に紹介します。
# - 15:24 2018/7/22
* 便利なオブジェクト
# 14:00 2018/7/23 -
** イントロダクション
第1章では、Rubyで扱う基本的なデータとして「文字列」と「数値」を取り上げましたが、Rubyで扱えるオブジェクトはこれだけではありません。多くのRubyのプログラムでは、もっと複雑なデータを扱うことになるでしょう。
Rubyでアドレス帳を作ることを考えてみます。アドレス帳に必要な項目は、
・名前 ・電話番号
・ふりがな ・メールアドレス
・郵便番号 ・SNSのID
・住所 ・登録日
といったところでしょうか。これらはいずれも文字列で表現できそうです。
これらの項目をひとまとめにすることで、1人分の情報になります。さらに、交友関係の人たちの情報が集まって、アドレス帳全体のデータが出来上がるわけです。
このようにデータとデータを合わせた1つのデータを表すには、これまでに紹介した「文字列」や「数値」といった単純なオブジェクト以外に、データの集まりを表現するデータ構造が必要になります。
この章では、「配列」と「ハッシュ」というデータ構造を紹介します。また、「正規表現」という、文字列処理に使われるオブジェクトも紹介します。
*メモ 配列やハッシュのようにオブジェクトを格納するオブジェクトを、コンテナやコレクションと言います。
配列・ハッシュ・正規表現はさまざまな場面で使われますが、より詳しい説明は後の章で行うことにして、ここではごく大まかにイメージをつかむことを目的に解説します。
** 配列(array)
*** イントロダクション
配列は「いくつかのオブジェクトを順序付きで格納したオブジェクト」として、もっとも基本的でよく使われるコンテナです。「配列オブジェクト」「Arrayオブジェクト」などと呼ばれることもあります。
*** 2.1.1. 配列を作る
新しい配列を作るには、要素をカンマ区切りで並べて、「[]」で全体を囲みます。まずは簡単な、文字列の配列を作ってみましょう。
names = ["小林", "林", "高野", "森岡"]
この例では、namesという配列オブジェクトが作られました。各要素として「"小林"」「"林"」「"高野"」「"森岡"」という4つの文字列を格納しています。
*** 2.1.2. 配列オブジェクト
配列の要素となるオブジェクトが決まっていない場合には、「[]」とだけ書くと、空の配列オブジェクトができます。
names = []
これ以外にも配列の作り方はいくつかあります。詳しくは「第13章 配列
(Array)クラス」で説明します。
*** 2.1.3. 配列からオブジェクトを取り出す
配列に格納されたオブジェクトには、位置を表す番号であるインデックスがつきます。このインデックスを使って、オブジェクトを格納したり、取り出したりできます。
配列の要素を取り出すには、
配列名[インデックス]
という構文を使います。例えば、namesという名前の配列オブジェクトを次のように作ったとします。
names = ["小林", "林", "高野", "森岡"]
配列namesの最初の要素である「小林」という文字列を取り出すには、
names[0]
と書きます。そのため、
print "最初の名前は", names[0], "です。\n"
という文を実行すると、
最初の名前は小林です。
と表示されます。同様に、names[1]は"林"、names[2]は"高野"になります。
実行例
> irb --simple-prompt
>> names = ["小林", "林", "高野", "森岡"]
=> ["小林", "林", "高野", "森岡"]
>> names[0]
=> "小林"
>> names[1]
=> "林"
>> names[2]
=> "高野"
>> names[3]
=> "森岡"
*メモ 配列のインデックスは0から始まります。1ではありません。ですから、a[1]と書くと、aという配列オブジェクトの先頭の要素ではなく、2番目の要素が返ってきます。慣れるまでは間違いやすいかもしれません(慣れていても間違いやすいところです)。注意してください。
*注 Windowsのコマンドプロンプトで日本語入力モードに切り替えるには、[半角/全角]キーを押します。
*** 2.1.4. 配列にオブジェクトを格納する
すでにある配列に、新しいオブジェクトを格納することもできます。
配列の要素の1つを別のオブジェクトと置き換えるには、
配列名[インデックス] = 格納したいオブジェクト
という構文を使います。先ほどの配列namesを使ってみましょう。先頭に"野尻"という文字列を格納するには、
names[0] = "野尻"
と書きます。例えば、次のように実行すると、namesの最初の要素が「野尻」になることがわかります。
実行例
> irb --simple-prompt
>> names = ["小林", "林", "高野", "森岡"]
=> ["小林", "林", "高野", "森岡"]
>> names[0] = "野尻"
=> "野尻"
>> names
=> ["野尻", "林", "高野", "森岡"]
オブジェクトの格納先として、オブジェクトのまだ存在しない位置を指定すると、配列の大きさが変わります。Rubyの配列は、必要に応じて自動的に大きくなります。
実行例
> irb --simple-prompt
>> names = ["小林", "林", "高野", "森岡"]
=> ["小林", "林", "高野", "森岡"]
>> name[4] = "野尻"
=> "野尻"
>> names
=> ["小林", "林", "高野", "森岡", "野尻"]
*** 2.1.5. 配列の中身
配列の中には、どんなオブジェクトも要素として格納できます。例えば、文字列ではなく数値の配列も作れます。
num = [3, 1, 4, 1, 5, 9, 2, 6, 5]
1つの配列の中に、複数の種類のオブジェクトを混ぜることもできます。
mixed = [1, "歌", 2, "風", 3]
ここでは例を挙げませんが、「時刻」や「ファイル」といったオブジェクトも、配列の要素にできます。
*** 2.1.6. 配列と大きさ
配列の大きさを得るには、sizeメソッドを使います。例えば、配列arrayに対して次のように使います。
array.size
sizeメソッドを使って、先ほどの配列オブジェクトnamesの大きさを調べてみましょう。
実行例
> irb --simple-prompt
>> names = ["小林", "林", "高野", "森岡"]
=> ["小林", "林", "高野", "森岡"]
>> names.size
=> 4
このように、配列の大きさが、数値として返ってきます。
*** 2.1.7. 配列と繰り返し
「配列の要素をすべて表示したい」とか、「配列の要素のうち、ある条件に当てはまる要素についてはxxメソッドを、当てはまらない要素についてはyyメソッドを適用したい」といったときには、配列の要素すべてにアクセスする方法が必要です。
Rubyには、このためのメソッドとして、eachメソッドが用意されています。eachメソッドは、第1章でも少し触れたように「イテレータ」というメソッドの1つです。
eachメソッドは、次のように使います。
配列.each do |変数|
繰り返したい処理
end
eachのすぐ後ろの「do ~ end」で囲まれている部分をブロックといいます。そのため、eachのようなメソッドは、ブロックつきメソッドとも呼ばれます。ブロックにはいくつかの処理をまとめて記述することができます。
ブロックの冒頭には「|変数|」という部分があります。eachメソッドは、配列から要素を1つずつ取り出して、「|変数|」で指定された変数に代入して、ブロックの中のメソッドを繰り返し実行していきます。
実際に使ってみましょう。配列namesにあるすべての要素を順番に表示してみます。
実行例
> irb --simple-prompt
>> names = ["小林", "林", "高野", "森岡"]
=> ["小林", "林", "高野", "森岡"]
>> names.each do |n| # do~endのように複数行にまたがる場合、
?> puts n endが入力されるまで実行されません
>> end
小林 # putsメソッドの実行結果
林
高野
森岡
=> ["小林", "林", "高野", "森岡"] # eachメソッドの戻り値
|n|となっている部分の変数nには、繰り返しの度に配列namesの要素が代入されます。
配列にはeachメソッドの他にもブロックを使うメソッドがたくさん用意されています。配列の要素をまとめて処理する場合によく使います。詳しくは「13.6 配列の主なメソッド」で取り上げます。
# 15:10
** ハッシュ(Hash)
ハッシュ(Hash)もよく使われるコンテナです。ハッシュでは文字列やシンボルなどをキーにしてオブジェクトを格納します。
address = {name: "高橋"m furigana: "タカハシ", postal: "1234567"}
*** 2.2.1. シンボルとは
シンボル(Symbol)というのは、文字列に似たオブジェクトで、Rubyがメソッドなどの名前を識別するためのラベルをオブジェクトにしたものです。
シンボルは、先頭に「:」をつけて表現します。
sym = :foo # これがシンボル「:foo」を表す
sym2 = :"foo" # 上と同じ意味
シンボルと同様のことは大抵文字列でもできます。ハッシュのキーのように単純に「同じかどうか」を比較するような場合は、文字列よりも効率が良いことが多いので、シンボルがよく使われます。
なお、シンボルと文字列はそれぞれ互いに変換できます。シンボルにto_sメソッドを使えば、対応する文字列を取り出せます。逆に、文字列にto_symメソッドを使えば、対応するシンボルを得られます。
実行例
> irb --simple-prompt
>> sym = :foo
=> :foo
>> sum.to_s # シンボルを文字列に変換
=> "foo"
>> "foo".to_sym # 文字列をシンボルに変換
=> :foo
*** 2.2.2. ハッシュを作る
新しいハッシュの作り方は、配列の作り方にちょっと似ています。配列と違うのは、「[]」の代わりに「{}」で囲むところです。また、ハッシュでは、オブジェクトを取り出すためのキーと、そのキーと対応させるオブジェクトを「キー => オブジェクト」という形式で指定します。キーにはシンボル、文字列、数理がよく使われます。
song = { :title => "Paranoid Android", :artist => "Radiohead" }
person = { "名前" => "高橋", "仮名" => "タカハシ" }
mark = { 11 => "Jack", 12 => "Queen", 13 => "King" }
とりわけシンボルがよく用いられるため、専用の短い書き方が用意されています。次の2つは同じ意味です。
person1 = { :name => "後藤", :kana => "ゴトウ" }
person2 = { name: "後藤", kana: "ゴトウ" }
*** 2.2.3. ハッシュの操作
ハッシュからオブジェクトを取り出したり、オブジェクトを格納したりする方法も、配列にそっくりです。ハッシュに格納されたオブジェクトを取り出すには、次の構文を使います。
ハッシュ名[キー]
また、オブジェクトを格納するには次の構文を使います。
ハッシュ名[キー] = 格納したいオブジェクト
配列と違って、キーには数値以外のオブジェクトも使えます。シンボルをキーにしたハッシュを操作してみましょう。
実行例
> irb --simple-prompt
>> address = {name: "高橋", furigana: "タカハシ"}
=> {:name=>"高橋", :furigana=>"タカハシ"}
>> address{:name}
=> "高橋"
>> address{:furigana}
=> "タカハシ"
>> address{:tel} = "000-1234-5678"
=> "000-1234-5678"
>> address
=> {:name=>"高橋", :furigana=>"タカハシ", :tel=>"000-1234-5678"}
*** 2.2.4. ハッシュの繰り返し
eachメソッドを使って、ハッシュのキーと値を1つずつ取り出し、すべての要素を処理することができます。配列の場合はインデックスの順に要素を取り出しましたが、ハッシュの場合は「キー」と「値」の組を取り出すことになります。
ハッシュ用のeachは次のように書きます。
ハッシュ.each do |キーの変数, 値の変数|
繰り返したい処理
end
早速使ってみましょう。
実行例
> irb --simple-prompt
>> address = {name: = "高橋", furigana: "タカハシ"}
=> {:name=>"高橋", :furigana=>"タカハシ"}
>> address.each do |key, value|
?> puts "#{key}: #{value}"
>> end
name: 高橋
furigana: タカハシ
=> {:name=>"高橋", :furigana=>"タカハシ"}
eachメソッドによって、ハッシュaddressが持っている項目名とその値を表示するputsメソッドが繰り返し実行されるのがわかります。
** 正規表現
Rubyで文字列を処理するときには、正規表現(Regular Expression)というものがよく使われます。正規表現を使うと、
・文字列とパターンの一致(マッチング)
・パターンを使った文字列の切り出し
などを手軽に行えます。
正規表現は、PerlやPythonなど、Rubyの先輩格にあたるスクリプト言語で培われてきた機能です。Rubyもその流れを受け継いでいて、言語に組み込みの機能として、手軽に正規表現を扱えます。文字列処理はRubyの得意分野ですが、それはこの正規表現のおかげでもあります。
*** 2.3.1. パターンとマッチング
「〇〇という文字列を含んだ行を表示したい」とか、「〇〇と××の間に書かれた文字列を抜き出したい」などといった、特定の文字列のパターンに対する処理を行いたい場合があります。文字列がパターンに当てはまるかどうかを調べることをマッチングといい、パターンに当てはまることを「マッチする」といいます。
このような文字列のパターンをプログラミング言語で表現するために使われるのが、正規表現です。
マッチングの例
/cde/ =~ "abcdefg"
「正規表現」という言葉から、何やら難しげな雰囲気が漂う、硬そうな印象を持たれるかもしれません。実際のところ正規表現の世界は何かと奥が深いのですが、単純なマッチングに使う分にはあまり身構える必要はありません。まずは、そういうものがあるということを覚えておいてください。
正規表現オブジェクトを作るための構文は、次の通りです。
/パターン/
例えば「Ruby」という文字列にマッチする正規表現は、
/Ruby/
と書きます。そのままですね。アルファベットと数字からなる文字列に一致するパターンを書く分には、「そのまま」で大丈夫です。
正規表現と文字列のマッチングを行うためには、「=~」演算子を使います。同じオブジェクト同士が等しいかどうかを調べる「==」に似ています。
正規表現と文字列のマッチングを行うには、
/パターン/ =~ マッチングしたい文字列
と書きます。英数字や漢字だけのパターンを使った場合は、パターンの文字列を含んでいればマッチし、含んでいなければマッチしません。マッチングが成功した時は、マッチ部分の位置を返します。文字の位置は、配列のインデックスと同様に、0から数えます。つまり、先頭文字の位置は0と表されます。一方、マッチングが失敗だとnilを返します。
実行例
> irb --simple-prompt
>> /Ruby/ =~ "Yet Another Ruby Hacker,"
=> 12
>> /Ruby/ =~ "Ruby"
=> 0
>> /Ruby/ =~ "Diamond"
=>nil
正規表現の右側の「/」に続けて「i」とかいた場合には、英字の大文字・小文字を区別せずにマッチングを行うようになります。
実行例
> irb --simple-prompt
>> /Ruby/ =~ "ruby"
=> nil
>> /Ruby/ =~ "RUBY"
=> nil
>> /Ruby/i =~ "ruby"
=> 0
>> /Ruby/i =~ "RUBY"
=> 0
>> /Ruby/i =~ "rUbY"
=> 0
これ以外にも、正規表現には数々の書き方や使い方があります。詳しくは「第16章 正規表現(Regexp)クラス」で説明します。
*** コラム「nilとは?」
nilはオブジェクトが存在しないことを表す特別な値です。正規表現によるマッチングの際に、どこにもマッチしなかったことを表す場合のように、メソッドが意味のある値を返すことができないときにはnilが返されます。また、配列やハッシュからデータを取り出す場合に、まだ存在していないインデックスやキーを指定すると次のようにnilが得られます。
実行例
> irb --simple-prompt
>> item = {"name"=>"ブレンド", "price"=>610}
=> {"name"=>"ブレンド", "price"=>610}
>> item{"tax"}
=> nil
if文やwhile文は、条件を判定するときにfalseとnilを「偽」の値として扱い、それ以外の全ての値を「真」として扱います。したがって、trueかfalseのどちらかを返すメソッドだけではなく、「何らかの値」もしくは「nil」を返すメソッドも、条件として使うことができます。
次の例は配列の中の「林」という文字を含む文字列だけを出力します。
List print_hayasi.rb
names = ["小林", "林", "高野", "森岡"]
names.each do |name|
if /林/ =~ name
puts name
end
end
実行例
> ruby print_hayasi.rb
小林
林
# - 16:20 2018/7/23
* コマンドを作ろう
** イントロダクション
この章では、コマンドラインからデータを受け取り、処理を行う方法を紹介します。また、第1部のまとめとして、Unixのgrepコマンドもどきを作成しましょう。Rubyプログラミングの大まかな流れをつかんでください。
** コマンドラインからのデータの入力
# 15:00 2018/7/24
今まで行ってきたことは、データを画面に出力することでした。「出力」があればその反対、「入力」も試してみたくなります。そもそも、普通に使えるコマンドを作るにはプログラムに動作を指示する方法を知らなければいけません。そこで、Rubyのプログラムにデータを入力してみましょう。
プログラムにデータを与えるには、コマンドラインを利用する方法が一番簡単です。コマンドラインの情報をデータとして受け取るには「ARGV」という配列オブジェクトを使います。このARGVという配列は、コマンドラインからスクリプトの引数として与えられた文字列を要素として持っています。
List3.1で確認してみましょう。コマンドラインでスクリプトに引数を指定するときは、1つずつ空白で区切って入力してください。
#+begin_src ruby
# List3.1 print_argv.rb
puts "最初の引数: #{ARGV[0]}"
puts "2番目の引数: #{ARGV[1]}"
puts "3番目の引数: #{ARGV[2]}"
puts "4番目の引数: #{ARGV[3]}"
puts "5番目の引数: #{ARGV[4]}"
#+end_src
#+begin_example
実行例
> ruby print_argv.rb 1st 2nd 3rd 4th 5th
最初の引数: 1st
2番目の引数: 2nd
3番目の引数: 3rd
4番目の引数: 4th
5番目の引数: 5th
#+end_example
配列ARGVを使えば、
データをプログラムの中にすべて書いておく必要は無くなります。
配列なので、要素を取り出して変数に代入することもできます。
#+begin_src ruby
# List3.2 happy_birth.rb
name = ARGV[0]
print "Happy Birthday, ", name, "!\n"
#+end_src
#+begin_example
実行例
> ruby happy_birth.rb Ruby
Happy Birthday, Ruby!
#+end_example
引数から取得したデータは文字列になっているので、
これを計算に使うときは数値に変換する必要があります。
文字列を整数にするには、to_iメソッドを使います。
+ to_i は to integer(整数へ)
List3.3 arg_arith.rb
#+begin_src ruby
num0 = ARGV[0].to_i
num1 = ARGV[1].to_i
puts "#{num0} + #{num1} = #{num0 + num1}"
puts "#{num0} - #{num1} = #{num0 - num1}"
puts "#{num0} * #{num1} = #{num0 * num1}"
puts "#{num0} / #{num1} = #{num0 / num1}"
#+end_src
実行例
> ruby arg_arith.rb 5 3
5 + 3 = 8
5 - 3 = 2
5 * 3 = 15
5 / 3 = 1
** ファイルからの読み込み
*** イントロダクション
Rubyのスクリプトが入力として受け取れるデータは、コマンドライン引数だけではありません。ファイルからデータを読み込むこともできます。
Rubyのソースコードには、「ChangeLog」というテキストファイルが付いています。これには、誰がどのようにRubyを変更したかが記してあります。
*メモ Rubyのソースコードは、Rubyの公式ウェブサイトから入手できます。Changelogファイルは、GithubのRubyレポジトリからも取得可能です。
・Rubyのソースコードダウンロード
https://www.ruby-lang.org/ja/downloads/
・Github上のChangelogファイル
https://raw.github.com/ruby/ruby/ruby_2_3/ChangeLog
このファイルを使って、Rubyでのファイル操作の練習をしてみましょう。
*** 3.2.1. ファイルからテキストデータを読み込んで表示する
まず、単純にファイルの中身をすべて表示するプログラムを作ってみましょう。ファイルの中身を表示するプログラムは、次のような流れになります。
1.ファイルを開く
2.ファイルのテキストデータを読み込む
3.読み込んだテキストデータを出力する
4.ファイルを閉じる
この流れを、そのままプログラムにしてみましょう。(List3.4)
List3.4 read_text.rb
#+begin_src ruby
filename = ARGV[0]
file = File.open(filename) # 1.
text = file.read # 2.
print text # 3.
file.close # 4.
#+end_src
今までの例に比べると、ちょっとプログラムらしくなってきました。1行ずつ説明します。
1行目では、filenameという変数にコマンドラインから受け取った最初の引数の値ARGV[0]を代入しています。つまり、変数filenameは読み出したいファイルの名前を示していることになります。
2行目で使っている「File.open(filename)」は、filenameという名前のファイルを開き、そのファイルを読み込むためのオブジェクトを返します。
……と言われても、「ファイルを読み込むためのオブジェクト」というのが何を意味しているのかよくわからないという方もいるかもしれません。あまり気にせず、ここではそういうオブジェクトがあるとだけ思ってください。詳しくは「第17章 IOクラス」で説明します。
この「ファイルを読み込むためのオブジェクト」が実際に使われるのは3行目です。ここでは、「read」というメソッドでデータを読み込み、その結果をtextに代入しています。ここでtextに代入されたテキストデータが、4行目で出力されます。printメソッドは今までにも何度も使ってきたので、もうすっかりおなじみのことでしょう。そして、最後に「close」というメソッドを実行します。これは、開いたファイルを閉じるためのメソッドです。
このプログラムを次のように実行すると、指定したファイルの内容をそのまま一気に表示します。
> ruby read_text.rb 表示したいファイル名
もっとも、ファイルを読み込むだけであれば、File.readメソッドを使うともっと簡単に書けます。(List3.5)
List3.5 read_text_simple.rb
#+begin_src ruby
filename = ARGV[0]
text = File.read(filename)
print text
#+end_src
File.readメソッドについても詳しくは「第17章 IOクラス」で説明します。
さらに、変数が不要であれば、1行でも書けます。(List3.6)
List3.6 read_text_oneline.rb
#+begin_src ruby
print File.read(ARGV[0])
#+end_src
*** 3.2.2. ファイルからテキストデータを1行ずつ読み込んで表示する
ここまでで、まとめて読み込んだテキストデータを表示することができるようになりました。しかし、先ほどの方法では、
・ファイルのデータをまとめて読み込むのに時間がかかる
・一時的にすべてのデータをメモリに貯めることになるので、大きなファイルの場合に困ることがある
といった問題があります。
100万行あるようなファイルでも、本当に必要なのは最初の数行だけ、ということもあります。そのような場合、すべてのファイルを読み込むまで何もしない、というのは、時間とメモリを無駄に使ってしまうことになります。
このような問題を解決するには、データを全て読み込んでから処理を開始するというアプローチをやめる必要があります。
・データをすべて読み込んでから処理する
ー>ファイル全体を収めるメモリ空間が必要
・一行ずつ読み込んで処理する
ー>メモリ空間は一行分でよい
List3.7 read_line.rb
#+begin_src ruby
filename = ARGV[0]
file = File.open(filename)
file.each_line do |line|
print line
end
file.close
#+end_src
1、2行目は、List3.4と同じです。3行目以降がちょっと変わっています。3行目から5行目はeach_lineメソッドを使っています。
each_lineメソッドは、第2章で紹介したeachメソッドに似たメソッドです。eachメソッドは配列の各要素をそれぞれ処理するメソッドでしたが、each_lineメソッドはファイルの各行をそれぞれ処理するメソッドです。ここではファイルを一行ずつ読み込み、その行の文字列lineをprintメソッドで出力することで、最終的にすべての行が出力されています。
*** 3.2.3. ファイルの中から特定のパターンの行のみを選んで出力する
Unixには、grepというコマンドがあります。これは、入力されたテキストデータの中から、正規表現で指定した特定のパターンにマッチする行を出力するコマンドです。これに似たコマンドを作ってみましょう。(List3.8)
List3.8 simple_grep.rb
#+begin_src ruby
pattern = Regexp.new(ARGV[0])
filename = ARGV[1]
file = File.open(filename)
file.each_line do |line|
if pattern =~ line
print line
end
end
file.close
#+end_src
List3.8を実行するには、次のように入力します。
> ruby simple_grep.rb パターン ファイル名
少し長くなったので、一行ずつ見ていきましょう。
Rubyを実行する際にコマンドラインで与えた引数は、ARGV[0]とARGV[1]に代入されます。1行目では、1つ目の引数ARGV[0]を元に正規表現オブジェクトを作り、変数patternに代入します。「Regexp.nre(str)」という形で、引数の文字列strから正規表現オブジェクトを作ります。そして2行目では、2つ目の引数ARGV[1]をファイル名に使う変数filenameに代入します。
4行目では、ファイルを開き、ファイルオブジェクトを作り、これを変数Fileに代入します。
5行目はList3.7と同じです。1行ずつ読み込んで変数lineに代入し、8行目までを繰り返します。
6行目はif文になっています。ここで、変数lineの値である文字列が変数patternの値である正規表現にマッチするかどうか調べます。マッチした場合、7行目のprintメソッドでその文字列を出力します。このif文にはelse節がないので、マッチしなかった場合は何も起こりません。
すべてのテキストの読み込みが終わったらファイルを閉じて終了します。たとえば、ファイルChangelogから「matz」という文字列が含まれている行を出力したい場合には、次のように実行します。
> ruby simple_grep.rb matz Changelog
「matz」とは、まつもとゆきひろ氏のニックネームです。まつもとゆきひろ氏による変更の履歴が出力されます。
# 16:18
** メソッドの作成
今までいくつかのメソッドを使ってきましたが、自分で作ることもできます。メソッドを作成する構文は次のようになります。
def メソッド名
メソッドで実行したい処理
end
「Hello, Ruby.」と表示するメソッドを作ってみましょう。
def hello
puts "Hello, Ruby."
end
この三行だけを書いたプログラムを実行しても、何も起こりません。helloメソッドが呼び出される前に、プログラムが終わってしまっているからです。そのため、自分で作成したメソッドを実行するコードも必要になります。
List3.9 hello_ruby2.rb
#+begin_src ruby
def hello
puts "Hello, Ruby."
end
hello()
#+end_src
実行例
> ruby hello_ruby2.rb
hello, Ruby.
「hello()」というメソッド呼び出しにより、1~3行目で定義されたhelloメソッドが実行されます。
** 別のファイルを取り込む
プログラムの一部を、別の新しいプログラムの中で使いまわしたいことがあります。たとえば、あるプログラムで使った自作メソッドを、別のプログラムで利用したい、と言った場合です。
たいていのプログラミング言語では、別々のファイルに分割されたプログラムを組み合わせて、1つのプログラムとして利用するための機能を持っています。他のプログラムから読み込んで利用するためのプログラムを、ライブラリといいます。
プログラムの中でライブラリを読み込むには、requireメソッドまたはrequire_relativeメソッドを使います。
require 使いたいライブラリのファイル名
または、
require_relative 使いたいライブラリのファイル名
使いたいライブラリのファイル名の「.rb」は省略することができます。
requireメソッドを呼ぶと、Rubyは引数に指定されたライブラリを探して、そのファイルに書かれた内容を読み込みます。ライブラリの読み込みが終わると再び、requireメソッドの次の行から処理を再開します。
requireメソッドは既存のライブラリを読み込むときに使います。ライブラリ名を指定するだけで、Rubyと一緒にインストールされたライブラリなど、あらかじめ決められた場所から探し出して読み込んでくれます。それに対してrequire_relativeメソッドは、実行するプログラムは置かれたディレクトリ(フォルダ)を基準にしてライブラリを探します。複数のファイルに分けて記述したプログラムを読み込むときに便利です。
実際の例として、先ほどのsimple_grep.rbの検索部分をライブラリとして、他のプログラムから使ってみましょう。ライブラリといっても別に変わった書き方は必要ありません。simple_grepメソッドを定義したファイル(List3.10)と、それを利用するプログラム(List3.11)を同じディレクトリに作成します。
List3.10 grep.rb
#+begin_src ruby
def simple_grep(pattern, filename)
file = File.open(filename)
file.each_line do |line|
if pattern =~ line
print line
end
end
file.close
end
#+end_src
List3.11 use_grep.rb
#+begin_src ruby
require_relative "grep"
pattern = Regexp.new(ARGV[0])
filename = ARGV[1]
simple+grep(pattern, filename)
#+end_src
simple_grepメソッドは検索するパターンとファイル名が必要なので、これらをpatternとfilenameという引数で受け取るようになっています。
grep.rbで定義したsimple_grepメソッドを、use_grep.rbで呼び出していることに注目してください。List3.8の実行例と同様に、ファイルChangelogから「matz」という文字列が含まれている行を出力したい場合には、次のように実行します。
> ruby use_grep.rb matz Changelog
Rubyには、たくさんの便利なライブラリが標準で付属しています。これらを利用する場合にrequireメソッドを使います。
たとえば、dateライブラリを読み込むことで、今日の日付を求めるDate.todayメソッドや特定の日付のオブジェクトを生成するDate.newメソッドなどを利用できるようになります。Rubyの誕生日である1993年2月24日から今日までの日数を求めるプログラムは次のようになります。dateライブラリについては第20章で詳しく説明します。
#+begin_src ruby
require "date"
days = Date.today - Date.new(1993, 2, 24)
puts(days.to_i)
#+end_src
*** コラム「ppメソッド」
pメソッドと同じような目的に使われるメソッドとして、ppメソッドがあります。ppは「Pretty Print」の略です。ppメソッドを利用するには、ppライブラリをrequireメソッドで読み込む必要があります。
List p_and_pp.rb
#+begin_src ruby
require "pp"
books = [
{ title: "猫街", author: "荻原翔太郎" },
{ title: "猫の事務所", author: "宮沢賢治" },
{ title: "猫語の教科書", author: "ポール・ギャリコ" },
]
p books
pp books
#+end_src
実行例
> ruby p_and_pp.rb
[{:title=>"猫街", :author=>"萩原翔太郎"}, {:title=>"猫の事務所", :author=>"宮沢賢治"}, {:title=>"猫語の教科書", :author=>"ポール・ギャリコ"}]
[{:title=>"猫街", :author=>"萩原翔太郎"},
{:title=>"猫の事務所", :author=>"宮沢賢治"},
{:title=>"猫語の教科書", :author=>"ポール・ギャリコ"}]
pメソッドとは異なり、ppメソッドはオブジェクトの構造を表示する際に、適当に改行を補ってみやすく整形してくれます。ハッシュの配列のように、入れ子になったコンテナを確認する場合に利用すると良いでしょう。
# - 17:00 2018/7/24