やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

TSVをHTMLのtableに変換する(C#)

 全機能を盛り込んだ完全版。

成果物

使い方

git clone https://github.com/ytyaru/CSharp.TsvToHtmlTable.20201028082641
cd CSharp.TsvToHtmlTable.20201028082641/src
./run.sh
./bin/tsv2table help

主な出力

 stdoutに以下のようなHTML文字列を出力する。

外側にヘッダがある表

ABC
abcde
AaABCDEFG
bHIJKLMN
BcOPQXRSTZaU
dVWYb
cdefghi
ejklmnop
Cqrstuvw

 ヘッダのみ空白セルでセル結合できる。包含関係を表現できる。

cat matrix_3.tsv | tsv2table

内側にヘッダがある表

ABC
abcde
AaABCDEFG
bHIJKLMN
BcOPQXRSTZaU
dVWYb
cdefghi
ejklmnop
Cqrstuvw
cat matrix_3.tsv | tsv2table i

ヘッダがない表

ABC
abcde
AaABCDEFG
bHIJKLMN
BcOPQXRSTZaU
dVWYb
cdefghi
ejklmnop
Cqrstuvw
cat matrix_3.tsv | tsv2table n

 他にもヘッダを両方につけたり、位置を変更したりできる。また、独自のHTML属性を与えることも可能。詳細はdemo参照。

使い方

 TSVをHTMLのtableに変換する。

cat a.tsv | tsv2table
tsv2table cat a.tsv

 CSVも使える。

cat a.csv | tsv2table -d ,
tsv2table -d , cat a.csv

 -dでデリミタを変えればTSV,CSV以外も使える。以下は|をデリミタにした。未指定ならタブまたはカンマのいずれかだと推測する。

echo -e '|A|B\n1|a|b\n2|c|d' | tsv2table -d "|"

 パイプやプロセス置換を使えば、文字列やコマンドを入力値にすることもできる。

echo -e '\tA\tB\n1\ta\tb\n2\tc\td' | tsv2table
tsv2table <(echo -e '\tA\tB\n1\ta\tb\n2\tc\td')

 CSV,TSVの1行目にシバンを含めることができる。tsv2tableをパスに通して、シバン付きCSVファイルに実行権限を付与。そして実行する。

git clone https://github.com/ytyaru/CSharp.TsvToHtmlTable.20201028082641
export PATH="$PATH":"$(pwd)/CSharp.TsvToHtmlTable.20201028082641/bin"
chmod + x ./CSharp.TsvToHtmlTable.20201028082641/docs/csv/col_3_shebang.csv
./CSharp.TsvToHtmlTable.20201028082641/docs/csv/col_3_shebang.csv

col_3_shebang.csv

#!/usr/bin/env -S tsv2table -H c
あ,A,a,A,B,C,D,E,F,G
,,b,H,I,J,K,L,M,N
,B,c,OP,,QX,R,STZa,,U
,,d,V,W,,Y,,,b
い,,,c,d,e,f,g,h,i
う,,e,j,k,l,m,n,o,p
,C,,q,r,s,t,u,v,w
<table><tr><th rowspan="4"></th><th rowspan="2">A</th><th>a</th><td>A</td><td>B</td><td>C</td><td>D</td><td>E</td><td>F</td><td>G</td></tr><tr><th>b</th><td>H</td><td>I</td><td>J</td><td>K</td><td>L</td><td>M</td><td>N</td></tr><tr><th rowspan="2">B</th><th>c</th><td>OP</td><td></td><td>QX</td><td>R</td><td>STZa</td><td></td><td>U</td></tr><tr><th>d</th><td>V</td><td>W</td><td></td><td>Y</td><td></td><td></td><td>b</td></tr><tr><th colspan="3"></th><td>c</td><td>d</td><td>e</td><td>f</td><td>g</td><td>h</td><td>i</td></tr><tr><th></th><th></th><th>e</th><td>j</td><td>k</td><td>l</td><td>m</td><td>n</td><td>o</td><td>p</td></tr><tr><th></th><th colspan="2">C</th><td>q</td><td>r</td><td>s</td><td>t</td><td>u</td><td>v</td><td>w</td></tr></table>

 その他、引数についてはdemo参照。

前回から解決したこと

  • シバン
    • TSV,CSVのシバンに書かれたtsv2tableのコマンドと引数を読み取って実行する
  • デリミタを推測する
    • テキスト内容に\t,,があるかどうか(両方あるなら各行で同じ数だけ存在するのはどちらか)
  • 出力パターンを追加した
    • ヘッダなし
    • ヘッダ内包パターン
      • 奇数列の全行がヘッダである
      • 偶数列の全行がヘッダである
      • 奇数行の全列がヘッダである
      • 偶数行の全列がヘッダである
      • 指定開始列から指定ステップ列数ごとの列が全行ヘッダである
      • 指定開始列から指定ステップ行数ごとの行が全列ヘッダである

課題

  • TSVのコメントアウト行を無視する(これは不要かも)
  • stdinとfile-pathの両方があったときはfile-pathを優先する(それがデフォルトだがヘルプに明記なし)
  • 実行ファイル単体だけで動くようにしたい(DLL, configファイル依存をなくしたい)
  • エスケープ

    • クォートした箇所は区切文字(改行、タブ、カンマ等)をエスケープするようにしたい
      • pythonみたいなshlex的ライブラリがない……
        • Microsoft.VisualBasic.dllTextFieldParserが参照できない……
  • 単体テストしていない

  • 列ヘッダを縦書きにしたい
    • 縦書きCSSを反映させるには<th>の中にテキストでなく<span>で囲ったテキストが必要である
      • 縦書き箇所だけ<span>を追加せねばならない
      • 縦書き用CSSが必要(HTML単独だけでは実現不可)
  • <td>CSS
    • 数値は左寄せ、文字列は右寄せにしたい
  • TSVからの複雑な変換
    • ある列を属性値にしたい
      • たとえばある列を<a>href属性値にしたい
  • HTMLを見やすいよう改行・インデントする別ツールが欲しい

所感

 単体テストしていないのはどうかと思う。でも結合テストでは問題なさそうだし、まあいっか。

 似たようなツールは探せばあるのだが、セル結合できるものがなかった。今回作ったツールはセル結合できる。そしてセル結合がキモ。セル結合するために面倒なアルゴリズムを書いた。もっと効率のいい書き方があると思う。

 突き詰めるとHTMLのtable,tr,th要素自体がクソ仕様。trのせいで行指向になってしまう。行、列、問わず好きにまとめることができたらうれしいのだが。きっと複雑になりすぎるから簡略化したのだと思う。

 複雑なHTMLへの変換は要検討。ムダにコマンドが複雑化しすぎてしまうと思われる。

 C#にていくつか外部ライブラリを使った。そこで不満が出たのでまとめたい。

対象環境

$ uname -a
Linux raspberrypi 5.4.72-v7l+ #1356 SMP Thu Oct 22 13:57:51 BST 2020 armv7l GNU/Linux