前回の Mrtable の紹介エントリ を書いてたときにもっとお手軽なものを思いつき、「あれっ、桁を揃えるだけならひょっとしてこんなので良かった?」と思ってしまったのでメモ。
こんなの:
[ "c1" , "c2" , "c3" , "c4" ] [ 1 , "a" , "" , null ] [ " " , "null" , 12.34 , "\\\t\r\n\"\\\t\r\n\"" ] [ 1234 , "全角テキスト" , "" , "" ]
要するに1行が1個の配列で、それを JSON にして、桁を揃えるだけ。頻繁に手書きするのでなければこれで十分では。
パースは行ごとに JSON.parse()
すればいい(実際これだけなのでライブラリ化する必要もないくらい)として、桁揃えも Mrtable のを流用すればすぐできそう、ということでちゃちゃっと書いてみました。
require 'json' module JsonArrayTable def self.parse(text) text.lines.map{ |line| JSON.parse(line) } end def self.generate(rows) num_cols = rows[0].size serialized = map_col_with_ci(rows) do |col, _| col.to_json end max_lens = (0...num_cols).map do |ci| col_len_max(serialized, ci) end padded = map_col_with_ci(serialized) do |col, ci| pad_col(col, max_lens[ci]) end lines = padded.map do |cols| "[ " + cols.join(" , ") + " ]\n" end lines.join("") end private def self.map_col_with_ci(rows) rows.map do |cols| indexes = (0...cols.size).to_a cols.zip(indexes).map do |col_ci| yield *col_ci end end end def self.col_len_max(rows, ci) rows .map{ |cols| col_len(cols[ci]) } .max end # 32-126(0x20-0x7E), 65377-65439(0xFF61-0xFF9F) def self.hankaku?(c) /^[ -~。-゚]$/.match?(c) end def self.col_len(col) col.chars .map{ |ci| hankaku?(col[ci]) ? 1 : 2 } .sum end def self.pad_right(s, n) rest = n - col_len(s) return s if rest == 0 s + (" " * rest) end def self.pad_left(s, n) rest = n - col_len(s) return s if rest == 0 (" " * rest) + s end def self.int?(s) /^\-?[\d]+$/.match?(s) end def self.pad_col(col, maxlen) if int?(col) pad_left(col, maxlen) else pad_right(col, maxlen) end end end
例:
require 'pp' text = <<-'EOB' ["c1", "c2", "c3", "c4"] [1, "a", "", null] [" ", "null", 12.34, "\\\t\r\n\"\\\t\r\n\""] [1234, "全角テキスト", "", ""] EOB rows = JsonArrayTable.parse(text) pp rows =begin [["c1", "c2", "c3", "c4"], [1, "a", "", nil], [" ", "null", 12.34, "\\\t\r\n" + "\"\\\t\r\n" + "\""], [1234, "全角テキスト", "", ""]] =end puts JsonArrayTable.generate(rows) =begin [ "c1" , "c2" , "c3" , "c4" ] [ 1 , "a" , "" , null ] [ " " , "null" , 12.34 , "\\\t\r\n\"\\\t\r\n\"" ] [ 1234 , "全角テキスト" , "" , "" ] =end
適当に JsonArrayTable
という名前にしましたが、もうこれでいいかな……命名のセンスなくて悲しみ。
JSON を抜かして array table とか……
誰かかっこいい名前を考えてください……。
(2021-04-18 追記) array table でいいかな……という気分になってきています。