ASCII コード表

全ての文字にはコードがつけられている。 16 進数表記で扱うと、ASCII コード表を参考にでき、便利である。

0123 4567 89ab cdef
0 nulsohstxetx eotenqackbel bshtlfvt ffcrsosi
1 dledc1dc2dc3 dc4naksynetb canemsubesc fsgsrsus
2 !"#$%&'()*+,-./
3 0123456789:;<=>?
4 @ABCDEFGHIJKLMNO
5 PQRSTUVWXYZ[\]^_
6 `abcdefghijklmno
7 pqrstuvwxyz{|}~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; リターン)

ASCII 文字コードの表示方法

プログラム上に書きこんで、文字コードで字を表示するには、

printf("%c \n",文字)

とする。 %c は 1 byte 分を表示する。 0xNN で 2 桁のコードがついているものが表示できるという意味である。 2 桁分で 1 byte を表す。

日本語の文字コード

日本語にも文字コードが存在する。Emacs で割り当てられた文字コードを調べてみよう。 Emacs で、知りたい文字の上にカーソルをあてて、 Ctrl-x = と入力する。ミニバッファに


Char: に (0151113, 53835, 0xd24b, file ...) point=2713 of 4394 (62%) column 12 

と出る。意味は

Char: 知りたい文字 (8 進数表示, 10 進数表示, 16 進数表示, file ...) エディタ上の場所

である。日本語は 16 進数 0xNNNN と読めるから、2 byte 必要としていることがわかる。

配列 Array

今まで習ってきた変数には、一つの情報が入った。 例えば、変数 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 次元配列という。次元がいくつかあってもよい。

2 次元配列

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 は組み合わせることができた。配列の 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 train if /(\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 += 1
end
end p first p change p second p fee i = 0 出力する経路を数える変数 while i < first.length
printf("経路%d: \n", i ) printf("東京からは%sに乗り%sで%sに乗り換えて酒田まで行きます\n",
first[i], change[i], second[i])
printf("料金は%d円です\n", fee[i])
i += 1
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
if /(\S+)\s+(\S+)\s+(\S+)\s+(\d+)/ =˜ train_data
price[n] = $4.to_i n += 1
end
end 低い運賃プランを選択する部分 low = price[0]とりあえずの最低運賃 nlow = 0最低運賃を持つ要素番号 i = 0最低運賃を調べる要素番号 while i < price.length-1
if price[i] < low
low = price[i] nlow = i
end i += 1
end 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 += 1
end
end

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 で、

%./実行するプログラム 読みこませたいデータ

とする。

cat コマンドを使用して実行する方法

続いて実行するというパイプ | で、 コマンドを 2 回連続使用し、

% cat 読みこませたいデータ | ./実行するプログラム

としてもよい。