Ruby体験記14 〜ハッシュ、シンボル、暗号

どうも。三十路です。

本日も2巻です。

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

ハッシュ

キーと値のペアで格納するオブジェクトをハッシュと呼ぶ。ハッシュの種類にはMD5やSHA256などがある。

require 'digest/sha2'

p Digest::SHA256.hexdigest(File.open($0,'rb').read)

シンボル

ハッシュリテラルを示す{}を省略することができ以下の用に記述できる。
obj.foo(:name=>"次郎さん", :city=>"東京")
name等の : 頭に付けたこの表記をSymbolクラスのオブジェクトリテラル表記です。
ちなみにnameがキーで次郎がそのキーの内容。

暗号

暗号とは安全に情報を伝達させるためにもちいるものであり、その目的としてデータの秘匿、なりすまし防御、改竄の防御の3つがある。現在の暗号の安全性は総当たりで解読できるまでの時間料によって安全性が保証されている。現実的な時間内に解読されなければ安全とみなしている。

Rubyで暗号化するにはopensslライブラリを利用する。

暗号化

  enc = OpenSSL::Cipher::AES256.new("CBC")
  enc.encrypt()   #複合するにはdecryptメソッドを使えばよい
  enc.pkcs5_keyivgen(pass)
  File.open(file, "rb") do |fin|
    File.open("#{file}.sec", "wb") do |fout|
      while buff = fin.read(8000)
        fout.write(enc.update(buff))
      end
      fout.write(enc.final())
    end
  end
  enc.reset()

そんな日。

Ruby体験記13 〜オブジェクトの永続化、圧縮

どうも。三十路です。

今日も2巻でお勉強。

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

オブジェクトの永続化

プログラム内部で作成したデータ(オブジェクト)をそのまま保存したり復元したりするのを永続化という。
Marshalモジュールを使うことで永続化することができる。
オブジェクトをバイナリ化(ようするに保存できる形式にすること?)することをマーシャルという。逆に復元することをデマーシャルという。

#マーシャル
t = Time.now
puts t
File.open "time_save.data", "wb" do |file|
  Marshal.dump t, file
end

#デマーシャル
t = nil
puts t
File.open "time_save.data", "rb" do |file|
  t = Marshal.load file
end
puts t

※全てのオブジェクトをマーシャル出来るわけではない。Fileオブジェクトなどはできない(OSに依存するので仮に保存しても他の環境では読み出せない。)

小問題1

#小問題1
array = [1, 2, 3, 4, 5]
File.open "array_save.data", "wb" do |file|
  Marshal.dump array, file
end
array = nil
puts array
File.open "array_save.data", "rb" do |file|
  array = Marshal.load file
end
puts "#{array}"

圧縮

データの内容を変えずに元のサイズよりもサイズを小さくすることを圧縮という。圧縮したデータを元に戻すことを復元または伸長、展開という。
元のデータと完全に同じように復元できる圧縮を可逆圧縮。また元には完全に戻せない圧縮を非可逆圧縮という。

def make_zero(count)
  r = ""
  if count > 1
    r = "Z#{count}"
  elsif count == 1
    r = "0"
  end
  r
end

def compress(nums)
  r = ""
  count = 0
  nums.each_char() do |c|
    if c == "0"
      count += 1
      if count == 10
        r << "Z0"
        count = 0
      end
   else
      r << make_zero(count)
      count = 0
      r << c
    end
  end
  r << make_zero(count)
end

aa = "3200000000008000000329000000000"
aa.each do |arg|
  puts "#{arg} => #{compress(arg)}"
end

require "zlib"
require "pp"

Zlib::GzipWriter.open "namelist.data.gz" do |gz|
  File.open "namelist.data", "rb" do |data|
    gz.write data.read
  end
end

Zlib::GzipReader.open "namelist.data.gz" do |gz|
  pp(Marshal.load(gz))
end

そんな日。

Ruby体験記12 〜通信、例外

どうも。三十路です。

本日も2巻。

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

通信

openメソッドにURIを指定する。

require "open-uri"

xml = nil
open "http://codezine.jp/rss/new/20/index.xml" do |http|
  xml = http.read()
end

例外

エラーを示す特別なオブジェクトを例外と呼ぶ。Rubyではプログラム実行時にエラーを発見すると、例外を関数やメソッドの呼び出し元へと送る。
begin〜endで囲い、rescueで発生した例外を受け取る。Errnoはエラー番号の略。ensureは最後に必ず実行したい処理をここへ記述、例外があった場合は例外が先に実行されてからensureが実行される。

begin
  File.open("aaaaaa") do |file|
    puts file.read
  end
rescue Errno::ENOENT => e
  puts e
rescue NameError => e
  puts e
rescue => e
ensure
  puts ""
end

そんな日。

Ruby体験記11 〜特殊変数、Array#each、String#each_char、条件式2、ライブラリの作成

どうも。三十路です。

本日も2巻。

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

特殊変数

Rubyでは共通で利用するオブジェクトを既定の特殊変数として参照可能にしている。

変数名 内容
$0 現在実行中のRubyプログラムのファイル名
$: require関数やload関数がライブラリをロードするために参照するフォルダ名の配列
$DEBUG デバッグモードならtrueが設定される変数。Rubyデバッグモードで実行するには-dを指定する
$stdin 標準入力。既定ではコンソール入力が割り当てられる
$stdout 標準出力。既定ではコンソール出力が割り当てられる
$stderr 標準エラー出力。既定ではコンソール出力が割り当てられる
$* Rubyプログラムに与えられた引数を格納した配列

Array#each

Array#eachメソッドとはブロック引数をとり、ブロック変数として配列内の要素を順番に与えて処理できる。

例)

array = "日,月,火,水,木,金,土".split(",")
array.each do |str|
  puts "#{str}"
end

上記をfor文で

array = "日,月,火,水,木,金,土".split(",")
for i in 0..array.size-1
  puts "#{array[i]}"
end

またインデックス値を1つずつ増やしたり、1つずつ減らしたりするのには、Integer#uptoやInteger#downtoのが処理が見やすくなるかもしれない。

String#each_char

先頭から末尾まで順に1文字ずつブロック変数に設定して、ブロック引数を呼び出す。

str= "日月火水木金土"
str.each_char do |s|
  puts "#{s}"
end

条件式2

条件が成り立たなければ処理するという条件分岐式がある。
以下2つは同じ意味である。
if !条件式
unless 条件式

ライブラリの作成

いままでどおりにプログラムを組むだけでそれをライブラリとして利用できる。その際にいくつか注意点。
ファイル名は全て小文字。またクラス名や関数名に「_」を利用している場合はファイル名には「-」を付ける。

そんな日。

Ruby体験記10 〜日付と時刻の扱い

どうも。三十路です。

今日も2巻。

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

日付と時刻の扱い

1970年1月1日9時からの経過した秒数を数値にして扱う。タイムゾーン指定もできる。(これって指定した国の1970年1月1日9時からの経過時間になるの? -> 1970年1月1月0時+タイムゾーンからの経過時間?)
TimeクラスとdateライブラリのDate,DateTimeで日付と時刻を扱える。

例)

now = Time.now
puts now

jt = Time.local(2009, 1, 1, 15, 32, 45)
puts jt
aprilfool = Time.local(2009, 1)
puts aprilfool

日付の表示形式はstrftimeで変更できる
例)

puts Time.now.strftime("%Y/%m/%d %X")

strftimeメソッドでの書式指定子

指定子 意味
%Y 年(1970から2038)
%y 年(下2桁)
%m 月(01から12)
%d 日(01から31)
%H 時(00から23)
%M 分(00から59)
%S 秒(00から59)
%x %m/%d/%y
%X %H:%M:%S
%c %x %X
%% テンプレート文字列内に%を含めたい場合

そんな日。

Ruby体験記9 〜ヘルプ、クラス、添付ライブラリ、メソッドチェイン、2次元配列、ブロックの簡易記法、エスケープシーケンス、降番順ループ、

どうも。三十路です。

本日でこの本での勉強も最後となりました。

プログラミング学習シリーズ Ruby 1 はじめてのプログラミング

プログラミング学習シリーズ Ruby 1 はじめてのプログラミング

つーても。シリーズものなのであと2冊あるんですけどね・・・。

いままでの内容、変数、関数、条件分岐、ループの手法を組み合わせたものは手続き型プログラミングというらしい。
名前なんぞどうでもいい気もするが一応覚えておく。
Rubyオブジェクト指向プログラミング言語なのでこれからはそれを勉強。

ってことで次の本にうつる。
最後の8章はファイルの扱いばかりなのでGoogle App Engineでは扱えないから読んでもいみなしぞうってことで飛ばす。

そんなわけで2巻。

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

Ruby 2 さまざまなデータとアルゴリズム (CD-ROM付) (プログラミング学習シリーズ)

へるぷ?とクラスと添付ライブラリ

Rubyには組み込みクラスと呼ばれる実行プログラム内に組み込まれたクラス群と、多数の独立したクラスをまとめた添付ライブラリというものがある。
これらを見るためにリファレンスマニュアルがある。以下のURLからダウンロードできる模様。
http://redmine.ruby-lang.org/wiki/rurema

メソッドチェイン

メソッド呼び出しを行いその戻り値がオブジェクトの場合、その戻り値のオブジェクトのメソッドを呼び出すことをメソッドチェインという。

2次元配列

配列の要素に配列が入れられたものを2次元配列という。さらに3次元以上つくることができこれらを総称して多次元配列という。

str = "あ,い,う,え,お"
sentences << str.split(",") #カンマ区で区切られたところで区切って配列を作り、その配列を配列の最後に追加する

配列の長さはsizeで得られる
sentences.size

ブロックの簡易記法

a = Array.new(10) do |i|
  Array.new(10, 0)
end
||>
を以下のように1行で記述可能
>|ruby|
a = Array.new(10) {|i| Array.new(10, 0)}

エスケープシーケンス

「\」はエスケープシーケンスの開始を示す文字。エスケープシーケンスとは現在の状態を一時的に離れて別の一連の処理を実行する制御を指す。
http://wisdom.sakura.ne.jp/programming/c/Cdata1.html

降番順のループ

Integer#downtoメソッドを使う。
以下の例はオブジェクトの値から引数(downtoメソッドの)で指定した値までの書く整数をブロック変数に入れながらブロックを実行する。1ずつ減らす。
3,2,1,0

3.downto(0) do |i|
end

その反対に以下の例は、オブジェクトの値から引数でしたいした値までの各整数をブロック変数に入れながらブロックを実行する。1ずつ増やす。
3,4,5,6

3.upto(6) do |i|
end

小問題5(P45)

1)

BITMAPFILEHEADER = "a2VIV"
BITMAPINFOHEADER = "VVVvvVVVVVV"
WIDTH = 640
HEIGHT = 480
FILEHEADER_LEN = 14
INFOHEADER_LEN = 40
COLOR_USED = 2
COLORTBL_LEN = 4 * COLOR_USED
HEADERS_LEN = INFOHEADER_LEN + FILEHEADER_LEN + COLORTBL_LEN

pas = Array.new(HEIGHT) {|i| Array.new(WIDTH, 0)}
pas[0][WIDTH / 2] = 1
for i in (1..HEIGHT - 1)
  for j in (1..WIDTH - 2)
    pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j + 1]
  end
end

File.open("pascal_rev.bmp", "wb") do |file|
  file.write(["BM", HEADERS_LEN + WIDTH * HEIGHT, 0, HEADERS_LEN].pack(BITMAPFILEHEADER))
  file.write([INFOHEADER_LEN, WIDTH, HEIGHT, 1, 8, 0, 0,
               0, 0, COLOR_USED, COLOR_USED].pack(BITMAPINFOHEADER))
  file.write("\xff\xff\xff\0")
  file.write("\0\0\0\0")
  (HEIGHT - 1).downto(0) do |y|
    0.upto(WIDTH - 1) do |x|
      if pas[y][x] % 2 == 0
        file.write("\x01")
      else
        file.write("\0")
      end
    end
  end
end

2)

BITMAPFILEHEADER = "a2VIV"
BITMAPINFOHEADER = "VVVvvVVVVVV"
WIDTH = 640
HEIGHT = 480
FILEHEADER_LEN = 14
INFOHEADER_LEN = 40
COLOR_USED = 2
COLORTBL_LEN = 4 * COLOR_USED
HEADERS_LEN = INFOHEADER_LEN + FILEHEADER_LEN + COLORTBL_LEN

pas = Array.new(HEIGHT) {|i| Array.new(WIDTH, 0)}
pas[0][WIDTH / 2] = 1
for i in (1..HEIGHT - 1)
  for j in (1..WIDTH - 2)
    pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j + 1]
  end
end

def bmpfile_write(pas, filename, color1, color2)
  File.open(filename, "wb") do |file|
    file.write(["BM", HEADERS_LEN + WIDTH * HEIGHT, 0, HEADERS_LEN].pack(BITMAPFILEHEADER))
    file.write([INFOHEADER_LEN, WIDTH, HEIGHT, 1, 8, 0, 0,
                 0, 0, COLOR_USED, COLOR_USED].pack(BITMAPINFOHEADER))
    file.write(color1)
    file.write(color2)
    (HEIGHT - 1).downto(0) do |y|
      0.upto(WIDTH - 1) do |x|
        if pas[y][x] % 2 == 0
          file.write("\0")
        else
          file.write("\x01")
        end
      end
    end
  end
end
bmpfile_write pas, "pascal_br.bmp", "\0\0\0\0", "\xff\0\0\0"
bmpfile_write pas, "pascal_wr.bmp", "\xff\xff\xff\0", "\0\0\xff\0"

3)

BITMAPFILEHEADER = "a2VIV"
BITMAPINFOHEADER = "VVVvvVVVVVV"
WIDTH = 640
HEIGHT = 480
FILEHEADER_LEN = 14
INFOHEADER_LEN = 40
COLOR_USED = 2
COLORTBL_LEN = 4 * COLOR_USED
HEADERS_LEN = INFOHEADER_LEN + FILEHEADER_LEN + COLORTBL_LEN

pas = Array.new(HEIGHT) {|i| Array.new(WIDTH, 0)}
pas[0][WIDTH / 2] = 1
for i in (1..HEIGHT - 1)
  for j in (1..WIDTH - 2)
    pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j + 1]
  end
end

File.open("pascal_mod5.bmp", "wb") do |file|
  file.write(["BM", HEADERS_LEN + WIDTH * HEIGHT, 0, HEADERS_LEN].pack(BITMAPFILEHEADER))
  file.write([INFOHEADER_LEN, WIDTH, HEIGHT, 1, 8, 0, 0,
               0, 0, COLOR_USED, COLOR_USED].pack(BITMAPINFOHEADER))
  file.write("\xff\xff\xff\0")
  file.write("\0\0\0\0")
  (HEIGHT - 1).downto(0) do |y|
    0.upto(WIDTH - 1) do |x|
      if pas[y][x] % 5 == 0
        file.write("\0")
      else
        file.write("\x01")
      end
    end
  end
end

そんな日。

Ruby体験記8 〜ハッシュ

どうも。三十路です。

今日も元気よくこの本でお勉強です。

プログラミング学習シリーズ Ruby 1 はじめてのプログラミング

プログラミング学習シリーズ Ruby 1 はじめてのプログラミング

ハッシュ

配列と同様にデータの管理する型。ハッシュはキーで管理する。

animals = {}
animals[""] = "わんわん"
animals[""] = "ニャーニャー"
animals[""] = "モーモー"
puts animals[""]
puts animals[""]
puts animals[""]

キーと値を => でつなぐこともできます。

animals = {
  ""=>"わんわん",
  ""=>"ニャーニャー",
  ""=>"モーモー"
}
puts animals[""]
puts animals[""]
puts animals[""]
練習問題

#7.1

def delete_multiple array, current, max
  a = current
  while a <= max
    array[a] = nil
    a += current
  end
end

def last_number array
  i = -1
  while !array[i]
    i -= 1
  end
  array[i]
end

MAX=100
puts "上限値は#{MAX}です"
nums = []
for i in 0..MAX
  nums << i
end

primes = []
for i in 2..MAX
  if nums[i]
    primes << i
    delete_multiple(nums, i, MAX)
    if i * i > last_number(nums)
      break
    end
  end
end

for i in 2..MAX
  if nums[i]
    primes << nums[i]
  end
end

puts "#{MAX}までの素数は#{primes}"

#7.2

PAPER=0
SCISORS=1
STONE=2
WIN={
  [PAPER, STONE] => true,
  [SCISORS, PAPER]=>true,
  [STONE, SCISORS]=>true
}
HANDS={PAPER=>"パー",SCISORS=>"チョキ",STONE=>"グー"}

com_win=0
plr_win=0
while com_win < 3 && plr_win < 3
  puts "パーは0、チョキは1、グーは2?"
  #choice = gets()
  choice = rand(3)
  player = Integer(choice)
  computer = rand(3)
  puts "あなた:#{HANDS[player]}, コンピューター:#{HANDS[computer]}"
  if WIN[[player, computer]]
    plr_win += 1
  elsif WIN[[computer, player]]
    com_win += 1
  else
    puts "あいこ"
  end
end

if plr_win >=3
  puts "あなたの勝ち"
else
  puts "あなたの負け"
end

そんな日。