mygems

壊れたCSVファイルの直し方|文字化け・1列になる原因

1列にまとまる、引用符のずれ、行の分断、文字化け。CSVの何が悪いのかを診断し、修復する方法を解説します。

執筆: uos ·

「壊れた」CSV(CSV file)の大半は、実は壊れていません。CSVはテキストファイルで、テキストファイルが劣化することはまずありません。ほとんどの場合、ファイルは書き出した側の前提で作られ、読み込む側が別の前提で開いています。区切り文字が違う、文字コードが違う、書き出しツールが引用符のルールを間違えた、といった具合です。

つまり、修復の前に診断が必要です。症状を見れば、6つの原因のどれなのかが分かり、それぞれに決まった直し方があります。

最短の答え

まず、スプレッドシートで開くのではなく、生のバイト列を確認してください。スプレッドシートは手がかりを隠してしまいます。

head -5 broken.csv          # the actual separators and quotes
file -I broken.csv          # the real encoding
wc -l broken.csv            # how many lines it thinks there are

そのうえで、症状から原因を探します。

症状原因対処
すべてが1列に入る区切り文字が違う区切り文字を指定して開き直す
é、’、üUTF-8をLatin-1として読んだUTF-8で開き直す
先頭の見出しに  が付くバイトオーダーマークBOMを取り除く
レコードの途中で行が分かれるフィールド内の改行引用符を直す
N行目以降で列数がずれるエスケープされていない引用符N行目を探して直す
行の途中でファイルが終わる書き込みが途中で切れた再エクスポートする

1. すべてが1列にまとまってしまう

圧倒的に多いパターンで、ファイルのせいではありません。

ヨーロッパ大陸の多くの地域では、カンマが小数点として使われるため、セミコロンが区切り文字になります。また、拡張子が .csv でも、実際にはタブ区切りの書き出しもたくさんあります。head -5 を実行すれば、どちらかすぐに分かります。

直し方は、読み込む側に区切り文字を教えることです。検索と置換で書き換えてはいけません。セミコロンをカンマに置換すると、引用符で囲まれた値の中のセミコロンまで置き換わり、本当に壊れたファイルになってしまいます。

  • Excel:ダブルクリックしないでください。データ → テキストまたはCSVからを選び、プレビューで区切り文字を指定します。
  • Googleスプレッドシート:ファイル → インポート → 区切り文字でカスタムを選びます。
  • コマンドライン:duckdb -c "SELECT * FROM read_csv('broken.csv', delim=';')"
  • スマートフォン:一度だけ推測して諦めるアプリではなく、解析設定を指定してファイルを開き直せるアプリを使います。
CSV Editor - Smart CSViPhone・iPad

区切り文字・ヘッダー・文字コードを自動判定します。推測が外れたときに、解析設定を自分で指定して開き直せる点が、ここでは特に重要です。

できること

2. 文字化け:é が é になる

典型的な文字コードの不一致です。ファイルはUTF-8なのに、Latin-1やWindows-1252として読まれています。バイト列は無傷で、解釈のほうが間違っています。

file -I broken.csv
# broken.csv: text/plain; charset=utf-8

直し方:UTF-8を指定して開き直します。Excelのインポート画面にはファイルの元の形式というドロップダウンがあるので、65001: Unicode (UTF-8) を選んでください。コマンドラインでは次のとおりです。

iconv -f WINDOWS-1252 -t UTF-8 broken.csv > fixed.csv

変換の向きに注意してください。ファイルが本当にWindows-1252(古いシステムや一部の基幹システムの出力)なら、このコマンドで変換できます。しかし、すでにUTF-8で、表示だけが間違っている場合は、変換するとかえって悪化します。文字化けした状態をエンコードしてしまうからです。何かを実行する前に、file -I で確認してください。

3. 最初の列名が order_id になる

UTF-8のバイトオーダーマークです。ファイルの先頭に付く3バイトの見えないデータで、Excelや多くのWindows系ツールが書き込みます。スクリプトでの見出しの照合を壊し、単純なパーサーでは文字化けのように表示されます。

sed -i '' '1s/^\xEF\xBB\xBF//' broken.csv    # macOS
sed -i '1s/^\xEF\xBB\xBF//' broken.csv       # Linux

取り除くのは、後続の処理が引っかかっているときだけにしてください。Excelは実際には、BOMを必要とします。ダブルクリックしたときにExcelがUTF-8のCSVだと判断する手がかりがBOMで、これを消したせいで、ファイルを送った相手のところで日本語やアクセント付きの文字が化けることがあります。

4. 行が途中で分かれてしまう

10,000行のはずが10,340行になり、住所があるべき場所に断片が入っています。住所、コメント欄、貼り付けた段落などが、フィールドの中に改行そのものを含んでいるのです。

フィールドが引用符で囲まれていれば、これは正しいCSVです。

id,name,notes
1,"Alice","Called back.
Wants a refund."

RFC 4180で認められており、きちんとしたパーサーなら問題なく処理できます。問題が起きるのは、ツールが引用符を考慮する前に改行で分割してしまう場合です。多くのシェルのワンライナー、一部のスプレッドシートのインポート機能、自作のコードの多くがこれに当たります。

直すべきなのは、たいていファイルではなく読み込む側です。引用符を理解するパーサーを使ってください。DuckDB、Pythonのcsvモジュール、csvkit、または本物のスプレッドシートのインポートなどです。フィールドが本当に引用符で囲まれていないなら、書き出し自体が壊れているので、修復するより再エクスポートのほうが早いでしょう。

どちらのケースか確かめるには、次を実行します。

csvclean -n broken.csv        # reports rows with the wrong field count

5. 4,812行目以降がすべておかしい

途中から列数がずれ、そのまま戻りません。原因はエスケープされていない引用符が1つあることで、それ以降はすべて、閉じられない文字列の中として読まれています。

id,product,price
1,"6"" pipe",4.50

この 6" は 6"" と書くべきでした。実際には、パーサーは値が 6 で終わると見なし、続く " が新しい値を開始して、ファイルの残りがその中に入ってしまいます。

見つけ方:

csvclean -n broken.csv
awk -F',' 'NF != 3 {print NR": "$0}' broken.csv   # rough, ignores quoting

確実なのは csvclean です。awk の行は、引用符内にカンマがないファイル向けの簡易的な近似です。行番号が分かったら、その1行だけを手で直します。内側の引用符を二重にするか、in. に置き換えて先へ進みましょう。

スマートフォンでは、特定の行にジャンプして1つのセルだけを編集できるアプリがないと、この作業は面倒です。

CSV File Viewer - Smart CSViPhone・iPad · Android

ファイル全体を開いて検索できるので、構造が崩れる行を見つけたうえで、修復するか再エクスポートするかを判断できます。

できること

6. ファイルが途中で終わっている

最後の行がレコードの途中で切れている、またはファイルサイズが妙にキリのいい数字になっている場合です。書き込みが中断されたか、ダウンロードが中断されています。

tail -3 broken.csv

ここで直せるものはありません。データはそもそも書き込まれていないからです。不完全な最終行を削除して欠損を受け入れるか、再エクスポートしてください。ダウンロードの場合は、ファイルを疑う前に、Content-Length と実際のサイズを比べましょう。

修復のルール

上記のほとんどを問題なく片付けられる、4つの習慣です。

  1. コピーで作業する。 cp broken.csv broken.backup.csv。このページの対処法は、確認するまではすべて推測です。元に戻せない推測は、割に合いません。
  2. ファイルより先に、読み込む側を直す。 ここで挙げた症状の多くは設定ミスです。間違ったパーサーに合わせてデータを書き換えると、問題が2つに増えます。
  3. 区切り文字を検索と置換で変えない。 引用符内の区切り文字まで置き換わり、読めるファイルが壊れたファイルになります。
  4. 前後で行数を数える。 どの修復でも行います。意図せず数が変わっていたら、修復で何かを壊しています。

諦めて再エクスポートするとき

構造的におかしい行が数行を超えるなら、修復はやめましょう。壊れた書き出しは、たいてい書き出し側の引用符処理にバグがあることを意味します。今は正常に見える行も含めて、そのツールが作るすべての行が疑わしくなります。ファイルをもう一度出してもらい、引用符付きで出力してもらってください。

よくある質問

CSVの中身がすべて1列に表示されるのはなぜですか?
読み込む側が想定した区切り文字と、ファイルの区切り文字が違うためです。ヨーロッパの多くの地域ではカンマが小数点なのでセミコロンが標準で、タブ区切りなのに拡張子が .csv のファイルも意外とよくあります。ファイルに head -5 を実行して実際の区切り文字を確認し、文字を置換するのではなく、その区切り文字を指定して開き直してください。
CSVで é のような変な文字が出るときはどうすればいいですか?
文字コードの不一致です。ファイルはUTF-8なのに、Latin-1やWindows-1252として読まれています。バイト列自体は問題ありません。`file -I` で実際の文字コードを確認し、UTF-8を指定して開き直してください。Excelのインポート画面では、ファイルの元の形式を 65001: Unicode (UTF-8) にします。iconv を使うのは、ファイルが本当にWindows-1252のときだけです。
CSVが途中から壊れるのはなぜですか?
ほぼ必ず、エスケープされていない引用符が1つあるためです。6" pipe のような値は、内側の引用符を二重にして書く必要があります。そうしないと、パーサーはそれ以降をすべて1つの巨大な文字列として読み、列数が元に戻りません。`csvclean -n` を使うと、フィールド数がおかしくなる最初の行を確認できます。
CSVファイルのフィールド内に改行を入れられますか?
はい。フィールドが引用符で囲まれていればRFC 4180で認められており、きちんとしたパーサーなら処理できます。行が途中で分かれて見えるのは、ツールが引用符を考慮する前に改行で分割しているためで、多くのシェルのワンライナーや一部のスプレッドシートのインポート機能がこれに当たります。ファイルを修復するより、本物のCSVパーサーを使ってください。
CSVファイルからBOMを取り除くにはどうすればいいですか?
Linuxでは `sed -i '1s/^\xEF\xBB\xBF//' file.csv`、macOSでは同じコマンドを `sed -i ''` にして実行します。後続の処理が引っかかっている場合だけ行ってください。ExcelはBOMを手がかりに、ダブルクリックしたファイルをUTF-8と判断します。そのため取り除くと、次にファイルを受け取る人のところで文字化けが起こります。
壊れたCSVをスマートフォンで修復できますか?
区切り文字や文字コードの問題なら可能です。解析設定を指定してファイルを開き直せるアプリを使えば、1バイトも変更せずに解決できます。エスケープされていない引用符のような構造的な破損では、問題の行を見つけてその1つのセルを編集する必要があります。できなくはありませんが手間がかかるため、数行を超えて間違っている場合は再エクスポートしてください。

uos — CSV EditorとSmart CSV Viewerを開発しており、他人の書き出しツールが間違えたCSVを数多く読んできました。