give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

CSVファイルのヘッダー行だけを置換するPerlワンライナー

はじめに

CSVファイルのヘッダー行だけを置換するPerlワンライナーを作ってみました。
下の例では列名に含まれるスペースをアンダーバーで置き換えています。
2行目以降のデータは置換されません。
DBD::CSVモジュールでは列名にスペースが入るとダメみたいなので、これを作りました。

ワンライナー
perl -0777pi -e 's/^([^\n]+)\n/join("_", split(" ", $1)) . "\n"/e' test.csv
置換前
COL 1,COL 2,COL 3
A 1,B 2,C 3
D 4,E 5,F 6
置換後
COL_1,COL_2,COL_3
A 1,B 2,C 3
D 4,E 5,F 6

ワンライナーの読み方

1行目だけを取得したいので、ワンライナーのオプションで「-0777」を指定してファイル全体を一つの文字列と見なしています。
さらに「^([^\n]+)\n」で一行目の文字列だけをキャプチャします。
続いてキャプチャした文字を置換するのですが、ここでは正規表現に「e」オプションを付けて置き換え文字列を式として評価しています。
replace($1, ' ', '_')みたいな関数がPerlには無いようなので、無理やりスペースでSplitしてからアンダーバーでjoinしました。


しかし、もっとスマートなやり方はたくさんあると思います。きっと。
0777オプションもファイルサイズが大きい場合は何か問題を起こしそうな気がしますし・・・。
スマートな書き方をご存知の方がおられれば、どうぞご教授ください m(_ _)m

2011.12.08 06:30追記

ちょっとだけ短くできました。

perl -0777pi -e 's/.+\n/join "_", split m| |, $&/e' test.csv


一行目を取得するところは「.+\n」だけでOKでした。
あと、splitで「/ /」とするとNGだったので、「" "」でsplitしていましたが、これだとなぜか最後の改行文字が消えてしまいました。
そこで、正規表現の区切り文字をスラッシュではなく縦棒(|)とするために、「m| |」としました。
最後に、これは短くするだけの目的ですが、joinやsplitに付いていた丸括弧を外しました。まあ、これは可読性が低下するので微妙なところですが・・・。


ホントは0777オプションを無くせたら一番スマートなんですけどねえ。