qedamameのブログ

PowerShellでCSVファイル編集


労働中に、大量のCSVファイルを作る必要があった。
行、列を微妙にずらしながら、値を変えていくにはどうしたら良いか。

私はシェルスクリプトを良く触るので、Linuxコマンドでどうにかできないかまず考えた。
結論から言うと、CSVファイルからデータを抜き出すことはできても、行列を指定した値の編集には向いていないようだった。
抜き出し方はいろいろあるが、どれも1行ずつファイルを読み込み、区切り文字を指定して列の値を取得する方法になる。
CSVファイルの列数が少ない場合は、以下はおすすめ。

while IFS=, read C1 C2 C3
do		
  echo "1列目は"${C1}
  echo "2列目は"${C2}
  echo "3列目は"${C3}
done < ${csv_file}


行番号の指定はできないので、ループ回数をカウントアップしていく必要がある。
で、任意の行の任意の列の値を取得したところで、これを編集する術がわからなかった。
あるとしたら、取得した値と編集後の値に区切り文字を付与し、1からファイルに書き出していくことになるだろう。
そんなやり方では処理が遅そうだし美しくないし、別の方法を考えた。
それは、PowerShellを用いる方法である。


# CSV読み込み
$csv_data = Import-Csv $before_csv -Encoding Default -Header @(1..3)

# 1行目の「1」列の値をhogeに変換
$csv_data[1].1 = "hoge"

# CSV出力
$csv_data | Export-Csv -NoTypeInformation $tmp_csv -Encoding Default

# CSVフォーマット調整(ヘッダ削除、ダブルクォート削除)
Get-Content $tmp_csv | Select-Object -Skip 1 | foreach { $_ -replace '"', '' } | Out-File -FilePath $after_csv -Encoding Default


コマンドレット Import-Csv を用いて、CSVオブジェクトにCSVファイルのデータをインポートする。
その後は、行と列を配列のように指定して、値を取り出したり、値を代入したりできる。
そのままではPSオブジェクト上のデータが書き換わっただけになるので、編集後は
コマンドレット Export-Csv を用いてファイルに出力する。

CSVオブジェクトには、必ずヘッダが必要らしい。
ヘッダつきのCSVファイルを用いる場合は気にしなくて良いが、ヘッダがない場合は -Header オプションで列名を指定する。
@(1..3) で、1~3の数字を列名として順番に指定できる。
ここでヘッダを付与したため、Export-Csv でファイル出力した際、ヘッダも含めて出力されてしまう。
そのため、一度ファイル出力したあとに、わざわざヘッダを削除している(Select-Object -Skip 1)。
さらに、すべての値がダブルクォーテーションで囲われてしまうので、 文字列置換をしてダブルクォーテーションを削除(foreach { $_ -replace '"', '' })。


…あまり美しくはない。
けれど、オブジェクトを介して非常に簡易に値の編集ができるのはすばらしい。


以上。