yn2011's blog

技術メモ

CSVファイル差分比較マニュアル

環境

やりたいこと

  • 2つのCSVファイルの差分比較をしたい
  • 差分がある場合は行単位ではなく列単位で分かるようにしたい
  • CSVファイル内のソートの差異や余分な行が含まれている等が原因で差分が発生している場合は直したい

以下、CSVファイルの差分比較を行う手順と注意事項を書いていく。

比較対象のCSVファイルを整形する

  • CSVファイルを比較可能な形に揃える作業
    • 自分の経験上、業務でCSVファイルの比較を行う場合は何らかの前処理(余分な行・列の削除、ソート)が必要なことが多い
  • シェルスクリプトで整形する
  • 正直Excelでもできるが、Excelで編集した途端に日付、ダブルクォート、真偽値(true, false)が勝手に大文字になる、先頭の0が消滅する等何らかの災いが発生するので使わないほうが賢明と思う
    • 比較する2ファイルともExcel通したら良いじゃんって話でもあるが、元データが意図せず破壊されることがある時点で何か気持ち悪い
    • 比較するファイルのサイズが大きい場合は実行効率の面でもシェルスクリプトが有利
      • 昔、2~3桁MBのCSVファイルの差分比較をしなければいけなくて、とりあえずExcelで開いたらExcelが重すぎて使えなくて焦ったことがあるが、シェルスクリプトで処理したらまったく問題にならなくて非常に助かった思い出がある

ソート

$ sort

補足

  • カラムが多すぎてソートに指定したい列が何番目か分からなかったりする場合のワンライナー
    • カラム名にカンマが含まれる場合は正規表現の改良が必要
    • もっとスマートなやり方がありそうな気がする(最後のカラムは表示されないし...)
cat hoge.csv | head -n 1 | sed -e 's/,/\n/g' | nl
     1  "都道府県コード"
     2  "都道府県名"
     3  "元号"
     4  "和暦(年)"

文字コード変換

  • Shift_JISだとターミナル上で日本語が文字化けする
# 文字コード判定
$ nkf -g hoge.csv
Shift_JIS
# UTF-8に変換(上書き)
$ nkf --overwrite -w hoge.csv

実際に比較する

git diff

  • こういうCSVファイルの場合
// test.csv
"1","2","3","4","5"
"6","7","8","9","10"
// test2.csv
"1","2","3","4","5"
"6","7","10","9","11"
  • 比較する(2行目の3列目と5列目に差異)
$ git diff --word-diff-regex="[^[:space:],]+" test.csv test2.csv
diff --git a/test.csv b/test2.csv
index bbe528b..e69d468 100644
--- a/test.csv
+++ b/test2.csv
@@ -1,2 +1,2 @@
"1","2","3","4","5"
"6","7"[-"8","9"-],"10",{+"9","11"+}
  • 確かに差分比較できているが、上記のようなケースだと2行目3・5列目に差異があることが明確に視認できない(気がするのは自分だけ?)

csvdiff

  • もっと良さげなのを探した

github.com

  • 3列目と5列目に差異が発生していることが明確に分かる
csvdiff test.csv test2.csv -o word-diff
# Additions (0)
# Modifications (1)
6,7,[-8-]{+10+},9,[-10-]{+11+}
  • また、このようにユニークキーを持つCSVファイルの場合は自動的にソート(比較行を選択)してくれる
// test3.csv
aaa, 1, 2, 3, 4, 5
bbb, 6, 7, 8, 9, 10
// test4.csv
bbb, 6, 7, 10, 9, 11
aaa, 1, 2, 3, 4, 5
$ csvdiff test.csv test2.csv -o word-diff -p 1
# Additions (0)
# Modifications (1)
bbb, 6, 7,[- 8-]{+ 10+}, 9,[- 10-]{+ 11+}
  • 比較したい列番号が予め分かっている場合は、その列だけで比較判定できる
$ csvdiff test.csv test2.csv -o word-diff -p 0 --columns 2
# Additions (0)
# Modifications (0)

まとめ

  • csvdiff便利そう