Programmer's Note

コード読み書きの備忘録。

Rubyのevalと正規表現で簡単にデータを取り込んでみる

Rubyのeval()を使ってみる。これを使えば、 ファイルから読み込んだ文字列データを、そのままRuby処理系に渡して解釈できる。

今回は、例えば適当に定義したデータ形式のファイルから、 hashテーブルとして読み込むところをやってみたい。

データは例えば下記のようなものとする。

human {
name: foo
age: 12
money: 120
}
dwarf {
name: boo
age: 200
money: 20
}

この程度なら難しいパーサーを作る必要もなく、文字列置換で以下に置き換えてしまう。

@list << {
'type'=>'human', 
'name'=>'foo', 
'age'=>'12', 
'money'=>'120', 
}
@list << {
'type'=>'dwarf', 
'name'=>'boo', 
'age'=>'200', 
'money'=>'20', 
}

これはもう下記のように正規表現でベタに置換してしまえばいい。 (標準入力から食わせた場合)

str = ''
while line = STDIN.gets
    case line
    when /^(.+?) {/
        str << "@list << {"
        str << "'type'=>'#{$1}', "
    when /(.+?): (.*?)$/
        str << "'#{$1}'=>'#{$2}', "
    when /(.+?):$/
        str << "'#{$1}'=>'', "
    else
        str << line
    end
end

あとは、evalにかけるだけ、

@list = []
eval(str)

と、Ruby内でhashテーブルの出来上がり。

さて、とりあえず上記のような形式のデータを変換して、 スペースで区切った形式に出力スクリプト(conv.rb)を作った。

■使い方:

$ cat data | conv.rb
TYPE NAME AGE MONEY
human foo 12 120
dwarf boo 200 20

ソースコード(conv.rb):

#!/usr/bin/ruby

def print_key(rcd, keys)
    rcd.each do |k,d|
        print "#{k.upcase} " if keys.length==0 || keys.include?(k)
    end
    puts ""
end
def print_record(rcd, keys)
    rcd.each do |k,d|
        _d = if d=="" then "-" else d end
        print "#{_d} " if keys.length==0 || keys.include?(k)
    end
    puts ""
end

#
# parse and import datas
#
str = ''
while line = STDIN.gets
    case line
    when /^(.+?) {/
        str << "@list << {"
        str << "'type'=>'#{$1}', "
    when /(.+?): (.*?)$/
        str << "'#{$1}'=>'#{$2}', "
    when /(.+?):$/
        str << "'#{$1}'=>'', "
    else
        str << line
    end
end

#
# make record data
#
@list = []
eval(str)

#
# print record date
#
print_key @list[0], ARGV if @list.length > 0
@list.each do |r|
    print_record r, ARGV
end