#!/usr/bin/env ruby22 # coding: euc-jp # CSV to table(HTML) converter - csv2table.rb # (c)2000, 2007, 2017 by HIROSE, Yuuji # $Id: csv2table.rb,v 1.7 2017/12/01 07:53:43 yuuji Exp $ # Last Modified Fri Dec 1 16:52:49 2017 on firestorm =begin CSVもしくはそれに準ずる(TAB区切りとの併用など)形式で書いた データファイルを HTMLの に変換する。HTMLテキストからは SSIによって csv2table.rb を利用することを想定している。 データファイルの先頭行のCSV列がtableの見出し(th)として扱われ、 見出し項目の後ろに :l :c :r をつけると対応する(二行目以降の)カラムが それぞれ 左寄せ、中央寄せ、右寄せ される。 例: *元ファイルが純正CSV(sample.csv) 氏名,住所,電話番号:r 慶應太郎,東京都港区,01-2345-6789 山口燃え,山口県防府市,09-9999-8765 ↓ ./csv2table.rb sample.csv ↓
氏名住所電話番号
慶應太郎東京都港区 01-2345-6789
山口燃え山口県防府市 09-9999-8765
データ区切りのカンマの前後に空白を許したいときは -s オプション カンマではなくTAB区切りにしたいときは -t オプションを利用する。 また、-e オプションにより特定のカラムの内容を、別カラムから生成すること ができる。利用できるマクロは以下の通り。 $n nカラム目の値に置換される $prev[n] nカラム目の直前の行の値に置換される $sum[n] nカラム目の直前の行までの総和 $diff[n] nカラム目の現在行と直前の行の差 (それぞれ [n] を省略するとカレントカラム指定になる) また、$ を利用したカラムがあると、そのカラムは上記置換をした上で数式 評価が行われる。しがたって、 単価:r,個数:r,金額:r 50,3,$0*$1 20,2,$0*$1 は、 +----+----+----+ |単価|個数|金額| +----+----+----+ | 50| 3| 150| +----+----+----+ | 20| 2| 40| +----+----+----+ という表に変換される。$n の置換は、数式置換が行われるよりも前に行われる ので数式の結果を $n で取り込むことはできないことに注意する。 大きな表で、スクロールさせると項目名が見えなくなる場合は行ガイド、列ガイド を出せる。 -row 20 とすると、20行毎に1行目と同じ行が出る。 -col 30 とすると、30カラムごとに1カラム目と同じ項目が出る(カラムガイド)。なお、 カラムガイドのtd要素には自動的に class="colguide" が付加されるので、HTML head要素内で などと記述しておけば、カラムガイド列が別の色になって判別しやすくなる。 さらに、デフォルトで奇数行のtr要素に class="odd"、偶数行のtr要素に class="even" が付加される。CSSで tr.even {background: #eff;} tr.odd {background: #dff;} などとしておけば1行おきに背景色を変えて見分けやすくすることができる。 その他のオプションは ./csv2table.rb -h で参照。 =end # 本体ここから require 'kconv' require 'csv' # デフォルト値 $border="0" $numbering=false $strip=false $colalign=[] $tabdelim=false $expand=false $rowguide=0 $colguide=0 def usage print <<_EOU_ #{$0} [options] CSV-files... Options are... -border N Set border width of the table to N -n Enable row numbering -t Accept TAB as a field delimiter -s Strip entry-surrounding white spaces -e Enable expression expansion ($sum[n], $diff[n], $prev[n], $n, and math-exp.) -row N Put heading line each N rows -col N Put column guide each N columns _EOU_ end while /^-([a-z]+)$/no =~ ARGV[0] case $1 when "border" ARGV.shift $border=ARGV[0] when "n" $numbering=true when "s" $strip=true when "t" $tabdelim=true when "e" $expand=true when "row" ARGV.shift $rowguide=ARGV[0].to_i when "col" ARGV.shift $colguide=ARGV[0].to_i when "h" usage; exit 0 end ARGV.shift end def putrow(list, n, elm = "td") cgclass=" class=\"colguide\"" rgclass=" class=\"rowguide\"" rowclass = if n > 0 " class=\"" + (n%2 == 0 ? "even" : "odd") + "\"" else "" end print " " if $numbering print "<#{elm} align=\"center\">" if n > 0 then print n else print "番号" end print "" end i=0 list.each{|l| if /\$\d/ =~ l l.gsub!(/\$(\d+)/){|n| list[$1.to_i]} l.strip! STDERR.print "---------------l=#{l}\n" if $DEBUG begin list[i] = l = (eval l).to_s rescue end STDERR.print "---------------l2=#{list[i]}\n" if $DEBUG end if /^[-0-9. ]+$/ =~ l $diff[i] = l.to_f - $prev[i].to_f if $prev[i] # $prev[i] = l.to_f $sum[i] += l.to_f end i+=1 } if $expand i=0 col0='' list.each{|l| l = l||"" $strip and l.strip! if l <= "" then l = "
" end l.sub!(/^[ \t]+$/, "
") out = l if $expand if /\$/ =~ l l.gsub!(/(sum|diff|prev)(?!\[)/){|n| n + "[#{i}]"} #if /(sum|diff)(?!\[)/ =~ l then l << "[i]" end print("--- l=[#{l}]\n") if $DEBUG l.gsub!(/\$(sum|diff|prev)\[(\d+)\]/){|x| eval("\$#{$1}[#{$2}]") } print("--- l2=[#{l}]\n") if $DEBUG out = eval("#{l}") # "$sum[i].to_s" end $nprv[i] = out if out.is_a?(Numeric) \ || (out.is_a?(String) && /^[0-9]+\.[0-9]+$/ =~ out) out = (sprintf("%10.2f", out)).to_f end end #STDERR.print("out -> #{out}\n"); col0=out if i==0 tdc = (i==0 ? cgclass : '') if i > 1 && $colguide > 0 && i%$colguide == 0 then print "<#{elm}#{cgclass}#{$colalign[i]}>#{col0}" end print "<#{elm}#{tdc}#{$colalign[i]}>#{out}" i+=1 } $prev[0..-1] = $nprv print "\n" end # 本体 count = 0 print "\n" # 一行目は見出し case ARGV[0] when /\.ods/i require 'roo' data = CSV.parse(Roo::OpenOffice.new(ARGV[0]).to_csv.toeuc) else str = ARGF.read.toeuc str.gsub!(/\t*,/, ",") if $tabdelim data = CSV.parse(str) end th = nil data.each do |l| next if /^$|^\#/ =~ l[0] # Skip Comment Line if count == 0 th = l $sum=Array.new(th.length, 0.0) $diff=Array.new(th.length, 0.0) $prev=Array.new(th.length, 0.0) $nprv=Array.new(th.length, 0.0) i=0 th.each{|e| if /:([lcr])$/io =~ e $colalign[i] = sprintf(" align=\"%s\"", {"l"=>"left", "c"=>"center", "r"=>"right"}[$1]) e.sub!(/:[lcr]$/, "") end i+=1 } putrow(th, 0, "th") else if $rowguide > 0 && count%$rowguide == 0 putrow(th, 0, "th") end putrow(l, count) if l end count+=1 end print "
\n"