Tcl/Tk 入門

カンマ区切りのデータでカンマクォートを許す

最終更新: [2005/11/03]
Copyright

Tcl で CSV データを扱うと…

データの可搬性の高い表現といえば CSV (comma separated value) 形式です. Tcl/Tk でデータを扱うときにもこれを採用したいところなのですが,ちょっと問題があります.

たとえば次のような3つのリストデータがあるとき

aaa bbb ccc
には,CSV 形式に変換するなら join コマンドを使えばいい
% join "aaa bbb ccc" ,
aaa,bbb,ccc
のですが,もしデータ自体にカンマが含まれていると join 後にはカンマがデータ自体のものなのか区切りなのか識別できなくなります.
% split [join "aaa b,bb ccc" ,] ,
aaa bb b ccc
当然ですね.このため一般にはデータとしてのカンマ記号はクォートして表現を保存します.

ところが,Tcl にはこの機能がないのです.

(※拡張パッケージが存在してました.下のリンクを参照下さい.ただし Tcl8.3 以上が必要のようです)

しゃーないので,CSV データとリスト間の変換プロシージャを書いてみました.csvsplit と csvjoin というコマンドです.プロシージャ名は下の am0250 から頂きました.

csvsplit/csvjoin

split 時にはダブルクォートで括られたカンマを \5 に強引に変換し,その他のカンマを使って split しています.ダブルクォートをデータに含める場合は2つ連続で書いて下さい.ソースはこちらです.
proc csvsplit {val} {
    regsub -all {""} $val "\3" val
    while {1} {
	if {[regsub {("[^",]+),([^"]+")} $val "\\1\5\\2" val]<=0} break
    }
    foreach x [split $val ,] {
	regsub -all "\3" $x {"} x
	regsub -all "\5" $x "," x
	regsub {^"(.*)"$} $x {\1} x
	lappend xx $x
    }
    return $xx
}

proc csvjoin {val} {
    if {[regsub -all {"} $val {""} val]<=0} break
    foreach x $val {
	if {[regexp "," $x]} {set x "\"$x\""}
	lappend xx $x
    }
    return [join $xx ,]
}

使用サンプル

使用例です.データはリンクにつけた標準 CSV ライブラリのページから取ってます.
% set aaa {123,"123,521.2","Mary says ""Hello, I am Mary"""}
123,"123,521.2","Mary says ""Hello, I am Mary"""

% puts org:$aaa                      ;# 元データ
org:123,"123,521.2","Mary says ""Hello, I am Mary"""

% puts spl:[join [csvsplit $aaa] |]  ;# splitデータ
spl:123|123,521.2|Mary says "Hello, I am Mary"

% puts joi:[csvjoin [csvsplit $aaa]] ;# そのjoin
joi:123,"123,521.2","Mary says ""Hello, I am Mary"""

リンク


||Tcl/Tk 入門||

Mail-to: oshiro@mibai.tec.u-ryukyu.ac.jp