hitode909の日記

趣味はマリンスポーツですの日記です

S式をArrayに格納するメソッドを書いた

サークルで作ってるプログラムで,サーバーとの通信をS式でやっているので,それで使う用。
ありがちなので探せば絶対ありそうだけど練習も兼ねて。

(a b)

というStringをちまちま置換して

["a", "b"]

というStringにして、evalを使ってArrayに変換した。
最初はスタックに入れたり出したりしながらやっていたのだけど、最終的にはこのような形に落ち着いた。
eval使えたのでよかったことにする。

#!/usr/bin/ruby
# S-Expression methods

# add to_sexp method.
class String
  def to_sexp
    # split the string with (,), .
    array = self.chomp.split(/([()])| /).delete_if{|c| c.size == 0}
    raise "The expression doesn't close." if array[-1] != ')'
    array.parse_sexp
  end

  def cut_each_end
    self[1..-2]
  end
end


class Array
  # this method returns s-expression string.
  def to_s_sexp
    str=""
    str += '('
    self.each do |s|
      str += ( s.class == Array ? s.to_s_sexp : s.to_s )
      str += ' '
    end
    str += ')'
    str
  end

  # parse s-expression and convert to array.
  def parse_sexp
    q = []
    q << '['
    self.each do |l|
      case l
      when '('
        q << '['
      when ')'
        q << '],'
      else
        q << '"' + l + '",'
      end
    end
    q << ']'
    return eval( q.join )
  end
end


# main
if __FILE__ == $0
  s=[]
  s << '(a b)'
  s << '(a)(b)'
  s << '(a(b(c)))'

  s.each do |l|
    puts l
    # convert s-exp-string to array
    p l.to_sexp
    # convert array to string
    puts l.to_sexp.to_s_sexp.cut_each_end
    puts
  end
end


これを実行すると

(a b)
[["a", "b"]]
(a b ) 

(a)(b)
[["a"], ["b"]]
(a ) (b ) 

(a(b(c)))
[["a", ["b", ["c"]]]]
(a (b (c ) ) ) 

が出る。
上から順に,入力のString,パースしたArray,パースしたArrayをStringに戻したもの。
たしかに正しく動いている(気がする)。