全ての文字にはコードがつけられている。 16 進数表記で扱うと、ASCII コード表を参考にでき、便利である。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | nul | soh | stx | etx | eot | enq | ack | bel | bs | ht | lf | vt | ff | cr | so | si |
1 | dle | dc1 | dc2 | dc3 | dc4 | nak | syn | etb | can | em | sub | esc | fs | gs | rs | us |
2 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
4 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
5 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
6 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
7 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | del |
表中、文字コード 0x00〜0x1fは、制御文字といい主に端末のコントロール をするための文字コードが並んでいる。例をあげておく。
0x00 | nul | 空文字 (文字列の終端を表すことが多い), null の略 |
0x07 | bel | 端末のベルを鳴らす, bell の略 |
0x08 | bs | バックスペース(BackSpace) |
0x09 | ht | 水平タブ(Horizontal Tab) |
0x0a | lf | 改行(Line Feed) |
0x1b | esc | エスケープ(Escape) |
0x0d | cr | 復帰(Carriage Return; リターン) |
プログラム上に書きこんで、文字コードで字を表示するには、
printf("%c \n",文字)
とする。 %c は 1 byte 分を表示する。 0xNN で 2 桁のコードがついているものが表示できるという意味である。 2 桁分で 1 byte を表す。
日本語にも文字コードが存在する。Emacs で割り当てられた文字コードを調べてみよう。 Emacs で、知りたい文字の上にカーソルをあてて、 Ctrl-x = と入力する。ミニバッファに
と出る。意味は
Char: 知りたい文字 (8 進数表示, 10 進数表示, 16 進数表示, file ...) エディタ上の場所
である。日本語は 16 進数 0xNNNN と読めるから、2 byte 必要としていることがわかる。
今まで習ってきた変数には、一つの情報が入った。 例えば、変数 truck に対して、名前や数値を代入した。
truck = データ
いわば、トラックにコンテナを積んでいる状態であった。 今度は、列車にコンテナが積まれている場合を勉強しよう。 これを配列という。一つの列車に対して、 いくつかコンテナを積んだ貨車で成り立つ。 配列 train に対して、
train[0] = データ 1
train[1] = データ 2
train[2] = データ 3
:
とデータが埋め込まれていく。 貨車は先頭が [0] から始まる。 配列[n] と表されるとき、 n (n=0,1,...) のことを添字 (index, indeces) と呼ぶ。 配列 train の具体的なデータが決まっている場合、
train = [データ 1, データ 2, データ3, ....]
と書くことができる。
もし、n 番目のデータを表示させたい場合は、プログラムには何と書けばよいか、
question = [1,2,3,4,5]
を表示させる printf
文を書き説明せよ。
n 番目のデータは配列の 第 n-1 要素 にある。 もしプログラム中に
train[1] = 新しいデータ
と書くと、配列は、
train[0] = データ 1
train[1] = 新しいデータ
train[2] = データ 3
:
と変更される。
配列の成分が一つしかないとき、 その中身はどのように書けているか。 printf 文を実行することによって調べよ。
添字の種類がいくつあるかを次元で数える。列車と考えた配列は添字が 1 種類しかない。 従って 1 次元配列という。次元がいくつかあってもよい。
apartment[i][j](i=0,1,.., j=0,1,..) という配列も可能である。
apartment[0] = [データ 1 の 1, データ 1 の 2, データ 1 の 3, ...]
apartment[1] = [データ 2 の 1, データ 2 の 2, データ 2 の 3, ...]
:
となる。apartment[i][j] はアパート i+1 階の j+1 号室にあるデータを意味する。
apartment = [ [データ 1 の 1, データ 1 の 2, データ 1 の 3, ...], [データ 2 の 1, データ 2 の 2, データ 2 の 3, ...] ]
という表記も可能である。
アパートの管理人になったつもりで、3 階立ての 4 部屋あるアパートの住人の氏名を入れたデータを作成せよ。 住人の氏名は適当に決めてよい。「N 階の M 号室には XX さんが住んでいます」 と表示させるプログラムにせよ (N,M には数値が入る)。
配列に入った情報の取り出し方を学ぼう。 ary_method.rb を作っていろいろ確かめよう。
prod = ["メロン","さくらんぼ","はえぬき"]
を使って調べよう。 p 文 を使って、配列の中身を調べながら進めていこう。
データの個数を調べるには、配列の要素の数を調べればよい。 ある配列 prod に対して、配列の要素の数を返す method は
prod.length (prod.size でもよい)
である。コンテナの中身に関わらず連結された車両の数を調べる method である。 prod.size または prod.length は、3 を返す。
先頭の成分を切り離すには、shift という method を使えばよい。 であれば、prod.shift は "メロン" となり、 prod 自体は
["さくらんぼ","はえぬき"]
となる。先頭車両のコンテナの中身を知らせ、切り放す method である。
ある配列 tel に対して、 小さい順に並べ換えた結果を返すには、sort を用いる。
price = [500, 600, 300]
であれば、
price.sort = [500, 600, 300]
となる。数字だけではなく文字列に対しても使える。
express = ["とき", "きらきらうえつ", "つばさ", "いなほ"]
のとき、
express.sort = ["いなほ", "きらきらうえつ", "つばさ", "とき"]
となる。
配列の要素の順番を逆にするには、
reverse
を用いる。
price.reverse = [300, 600, 500]
となる。
変数を扱う method は組み合わせることができた。配列の method も price.sort.reverse のように、組み合わせて結果を得ることができる。 price.sort.reverse は数の大きな順から並び換える method である。
price.sort.reverse = [600, 500, 300]
を得る。
なぜ数の大きな順から並び替えることを意味するのか、順を追って説明せよ。
文字列の配列で sort.reverse を実行すると、名簿の逆順を出力する。
express = ["とき", "きらきらうえつ", "つばさ", "いなほ"]
ならば、
express.sort.reverse = ["とき", "つばさ", "きらきらうえつ", "いなほ"]
を返す。
express.sort.reverse がなぜ名簿の逆順を出力するのか、 順を追って説明せよ。
数字の大小と同じように文字コードに大小を使って並び替えが可能である。
なぜ日本語の配列でも並び替えが可能なのか、 適宜文字コードを調べながら並び替えについて解説せよ。
文章が決まっていて、 中身を入れ替えるだけのプログラムが動作しているものを考えよう。 たとえば、行先検索ソフトはこの例に当たる。 行先案内の例は、例えばこのように表示されるだろう。
%./ary_train.rb[˜/Ruby] 東京から酒田へ行く方法を探します: 経路 1: 東京からはつばさに乗り、新庄で陸羽西線に乗り換えて酒田まで行きます。 運賃は13350 円です。 経路 2: 東京からはときに乗り、新潟でいなほに乗り換えて酒田まで行きます。 運賃は 13880 円です。 経路 3: 東京からはときに乗り、新潟できらきらうえつに乗り換えて酒田まで行きます。 運賃は 12790 円です。 経路 4: 東京からは羽田空港で飛行機に乗り、庄内空港でバスに乗り換えて酒田まで行きます。 運賃は 22810 円です。
中身が入れ替わっているだけで同じ文章が使われているのがわかるだろうか。 実際は条件を絞ることにより膨大なデータを調べ上げて、 結果を導き出すが、ここでは東京 -- 酒田間に限ってモデルを作る。
東京から酒田までの、 行先案内方法を絞らずに結果表示するプログラムを作る。 行先検索ソフトの原型となる。 ary_train.rb
#!/usr/koeki/bin/ruby
#coding: euc-jp
i = 0 # 経路の番号をしまう
first = ["つばさ","とき","とき","羽田空港で飛行機"] はじめに乗る列車
change = ["新庄", "新潟", "新潟" ,"庄内空港"] 乗り換え先
second = ["陸羽西線","いなほ","きらきらうえつ","バス"]次の列車
fee = [13350, 13380, 12790, 22810]料金
print("東京から酒田へ行く方法を探します: \n")
while i < first.length
printf("経路%d: \n", i+1 )
printf("東京からは%sに乗り%sで%sに乗り換えて酒田まで行きます\n",
first[i], change[i], second[i])
printf("料金は%d円です\n", fee[i])
i += 1
end
print("検索終了\n")
入力するデータが増加してきた場合を考えよう。 データをプログラム内に収める今の方法のままでは、 プログラムの中身がよく分からなくなる。 データはデータで独立させ、 データを読み込ませてプログラムを動かせるようにしよう。 データとプログラムの分離はこちら
データは、文字列を空白で分けて作成する。 空白は Tab キーで作ると作業が早く進む。 train.dat
つばさ | 新庄 | 陸羽西線 | 13350 |
とき | 新潟 | いなほ | 13880 |
とき | 新潟 | きらきらうえつ | 12790 |
羽田空港で飛行機 | 庄内空港 | バス | 22810 |
改良版 ary_stdin.rb を作る。
#!/usr/koeki/bin/ruby #coding: euc-jp first = Array.new 最初に乗る列車名 change = Array.new 乗り換え先 second = Array.new 次に乗る列車名 fee = Array.new 料金 n = 0 経路をしまう変数 while train = gets
p trainend p first p change p second p fee i = 0 出力する経路を数える変数 while i < first.lengthif /(\S+)\s+(\S+)\s+(\S+)\s+(\d+)/ =˜ train
p train first[n] = $1 change[n] = $2 second[n] = $3 fee[n] = $4.to_i n += 1endprintf("経路%d: \n", i ) printf("東京からは%sに乗り%sで%sに乗り換えて酒田まで行きます\n",
first[i], change[i], second[i])i += 1printf("料金は%d円です\n", fee[i])
end print("検索終了\n")
Array.new
配列を新規につくる method
実行方法と使われている仕組みをそれぞれみてみよう。
データを取り込みながら表示するには、Kterm でデータを指定する必要がある。 gets の部分で、読ませるデータを 1 行ずつ読むので、
%./ary_stdin.rb train.dat
とする。
% ./プログラム.rb 読ませるデータ.dat
while -- end
では、
train_data
という変数に、
gets
でデータを 1 行取り込んできて代入する。
if -- end
では、
train_data
という変数に入っているデータを分解する。
データの並びが
データ TAB による空白 データ TAB による空白 データ TAB による空白 データ
という組み合わせであることを確認して、 次でデータの分解方法を見ていこう。
実際の検索プログラムでは順番にデータを吐き出すだけであろうか。 他に機能がないか思い出そう。
データの分解は、 / / で挟んだパターンが入っているかどうか調べることによって行われる。
if /パターン/ =˜ 変数変数がパターンに一致するならば
=˜ は指定された正規表現が一致するかどうかを調べるときに使う比較演算子である。 正規表現とは、文字列の一致を調べる方法である。 今の場合は以下の正規表現が使われている。
\S+ | 文字列の連続 |
\s+ | 空白文字の連続 |
\d+ | 数値文字列の連続 |
() | () 内に含まれる文字列を優先して探す |
数値文字列を探して取り込む正規表現で取り込んだ中身を
p
文で確認せよ。数値を取り込んだ場合、文字列を取り込んだ場合の結果を確認せよ。
正規表現は次週にも続く。 さて、文字列が空白文字を挟んで 4 回現れるため、
if /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/ =˜ 変数
となっている。() で優先された文字列は $1, $2, .. と順番に名前をつけられ、それらが配列の各成分として代入されている。
/(優先された文字列 1)優先されない文字列(優先された文字列 2)優先されない文字列 ... / =˜ 変数
# $1 は 優先された文字列 1 を引き取る
# $2 は 優先された文字列 2 を引き取る
:
データが 5 列で並んでいる場合は、 どのように分解する部分を書き換えたらよいだろうか。
+
をつけて文字列や数字の列、空白列をとりだすことができる。
\s+ | 空白文字列 |
\S+ | 文字列 |
\d+ | 数文字列 |
切り出したものを整数値に変換するには、 to_i method を使う必要がある。
整数値の含まれるデータを作り、 データを読み込んで平均を求めるプログラムを作ってみよう。
小数点の含まれる数字の列を切り出すには、
.
の左右に空白文字列なしで数文字列が並んでいる。
meta character で役割を持つ文字列を通常の文字として探すためには、
\
をつける。
\d+\.\d+
整数になる文字列.小数になる文字列
などとしなければならない。 これを小数値に変換するにはいったんとりこんだ文字列に to_f method を使う必要がある。
小数点が含まれるデータを作り、 データを読み込んで平均を求めるプログラムを作ってみよう。
p 文を使うと、配列の中に何が入っているのか、調べることができる。 配列にしまうとき、計算機は計算機用にデータをしまうため、 ユーザが取り出したいときは、EUC-jp に漢字コードを変換しておく必要がある。
設定はプログラムの上の方に記す。 慣習に沿っているので読みやすいプログラムであると判断される。
今日出てきた method で得られる結果を表示させながら自分でも確かめてみよう。
最低運賃のプランを出すには、運賃の列を比較して、表示すればよい。 データが 1 行に詰められているので、最低運賃の列を縦にしまい、 その要素番号を記録して他のデータを表示することにする。 まずは最低運賃だけを表示させよう。ary_lowest.rb
#!/usr/koeki/bin/ruby #coding: euc-jp price = Array.new 運賃価格をしまう配列 n = 0 データをしまう部分 print("東京から酒田へ行く方法を探します:\n") while train_data = gets
end 低い運賃プランを選択する部分 low = price[0]とりあえずの最低運賃 nlow = 0最低運賃を持つ要素番号 i = 0最低運賃を調べる要素番号 while i < price.length-1if /(\S+)\s+(\S+)\s+(\S+)\s+(\d+)/ =˜ train_data
price[n] = $4.to_i n += 1endif price[i] < lowlow = price[i] nlow = iend i += 1end printf("最も運賃が低いプランです\n") printf("\t 運賃は %d 円です\n", price[nlow])
nlow と配列を使って、同じデータ行にあるデータを表示させよう。 完成はこちら。
最低運賃だけではなく、プランをまるごと表示させよう。
dept = Array.new出発地をしまう配列 trans = Array.new乗換地をしまう配列 arvl = Array.new当着地をしまう配列 price = Array.new運賃価格をしまう配列 n = 0 データをしまう部分 print("東京から酒田へ行く方法を探します:\n") while train_data = gets
if /(\S+)\s+(\S+)\s+(\S+)\s+(\d+)/ =˜ train_data
dept[n] = $1 trans[n] = $2 arvl[n] = $3 price[n] = $4.to_i n += 1endend
p 文を実行し、 配列に値を取り込んだことを確認したら、 結果表示をする部分を付け加えて完成させよう。
printf("最も運賃が低いプランです\n") printf("東京からは %s に乗り、%s で %s に乗り換えて酒田まで行きます \n",
dept[nlow],trans[nlow],arvl[nlow])printf("\t 運賃は %d 円です\n",price[nlow])
印刷ボタンを押すと簡単に印刷するソフトウェアが多いが、 中のしくみはどうなっているのだろうか。
印刷: ファイル全体を Postscript 言語に変換して印刷する
機械の中ではコマンドが働いており、
% cat データ | 印刷するコマンド
となっている。| は、連続して実行するときに使うもので、 redirect という。 前に実行したコマンドの成功不成功は問わない、という意味である。
4 例しか出力しないような小さなプログラムでは、 配列に情報をしまったプログラムでも混乱はないが、 多数の例を一度に読み込ませて出力することができるなら、 読み込ませるプログラムは短いので、変更しやすい。 またデータ部分だけ増強すればよいので、その点でも便利である。 データ部分を増強した場合、
つばさ | 新庄 | 陸羽西線 | 13350 |
とき | 新潟 | いなほ | 13380 |
とき | 新潟 | きらきらうえつ | 12790 |
羽田空港で飛行機 | 庄内空港 | バス | 22810 |
: | : | : | : |
夕陽号 | 酒田南ジャスコ | 長距離バス | 7740 |
となる。このデータをを読ませるには、同様に Kterm で、
%./実行するプログラム 読みこませたいデータ
とする。
続いて実行するというパイプ | で、 コマンドを 2 回連続使用し、
% cat 読みこませたいデータ | ./実行するプログラム
としてもよい。