「CSVファイルにダブルクォートを含むデータを書き込んだら、エラーになってしまった…」
「JSON文字列をCSVに変換したら、『Unexpected character』や『Invalid JSON format』というエラーが出て困っている…」
実はこの問題の原因は、CSVでのダブルクォーテーションのエスケープ方法を間違えていることなんです。
JSONではバックスラッシュ(\)でエスケープするのに、CSVでは全く違うルールが使われているため、多くの方が混乱してしまいます。
私も最初は「なんでJSONのエスケープが効かないんだ?」と悩みました。
本記事では、CSVファイル中でのダブルクォーテーションの正しいエスケープ方法を、具体例とともに分かりやすく解説します。
この記事を読めば、JSONのCSV化を含め、CSVファイル中でのダブルクォーテーションの扱いを完全に理解できるようになります!
JSONのエスケープ方法(\")はCSVでは使えない
CSVではダブルクォート(")が特別な意味を持つ文字です。
CSVパーサーは、ダブルクォートを見つけると「この中身は1つのフィールドだ」と判断します。
カンマや改行が含まれていても、ダブルクォートで囲まれた部分は1つのデータとして扱われます。
しかし、フィールド内にダブルクォートそのものを含めたい場合に問題が発生します。
普通にダブルクォートを書いてしまうと、CSVパーサーが「ここでフィールドが終わった」と勘違いしてしまい、エラーになってしまいます。
ここで多くの方が混乱するのが、JSONとCSVでエスケープ方法が全く違うことです。
JSONでは、ダブルクォートをエスケープする際にバックスラッシュを使います(例:\")。
しかし、CSVではこの方法が通用しません。
CSVパーサーは\"を見ても「エスケープされたダブルクォートだ」とは解釈してくれないため、JSONのエスケープ方法をそのまま使うと、エラーになってしまいます。
CSVではダブルクォートを2つ重ねてエスケープする("")
CSVでダブルクォートをエスケープする正しい方法は、ダブルクォート(")を2つ重ねます。
1つのダブルクォート文字を表現したい場合は、""と書きます。
CSVパーサーは、この""を見つけると「これは1つのダブルクォート文字だ」と自動的に解釈します。
これは、CSV標準(RFC4180)で定められた正式なルールです。
また、フィールド内にカンマや改行が含まれている場合、そのフィールド全体をダブルクォートで囲む必要もあります。
この場合、フィールド内のダブルクォートは全て二重化します。例えば、「こんにちは"世界"」という文字列をCSVに書き込む場合、"こんにちは""世界"""と記述します。
JSON文字列の書き方:全体を囲み、内部のダブルクォートを二重化する
JSON文字列全体をダブルクォートで囲む
JSON文字列をCSVに変換する際は、まずJSON文字列全体をダブルクォートで囲む必要があります。
理由は、JSON内にカンマ(,)が含まれているためです。CSVではカンマがフィールドの区切り文字として使われるので、JSON文字列がダブルクォートで囲まれていないと、CSVパーサーが途中でフィールドが区切られていると勘違いしてしまいます。
例えば、{"name":"田中","age":30}というJSON文字列をそのままCSVに書くと、CSVパーサーは最初のカンマを見つけた瞬間に「ここでフィールドが区切られた」と判断してしまい、JSON文字列がバラバラに分割されてしまいます。
そのため、"{"name":"田中","age":30}"のようにJSON文字列全体をダブルクォートで囲みます。
3.2 JSON内のダブルクォートを二重化する
JSON文字列全体をダブルクォートで囲んだら、次にJSON文字列内の全てのダブルクォートを二重化します。
JSONでは、キーや文字列値の前後にダブルクォートが使われています。これらを全て""に置き換える必要があります。
例えば、{"name":"田中","age":30}というJSONをCSVに変換する場合、以下のようになります:
id,json_data
1,"{""name"":""田中"",""age"":30}"JavaScriptJSON内の全てのダブルクォート(")が、""に置き換わっているのが分かりますね。
複雑なJSONの変換例
配列やネストしたオブジェクトを含む複雑なJSONでも、基本的なルールは変わりません。
全体をダブルクォートで囲んで、内部のダブルクォートを全て二重化するだけです。
id,user_data,tags
1,"{""name"":""佐藤"",""email"":""sato@example.com""}","[""tag1"",""tag2""]"
2,"{""name"":""田中"",""address"":{""city"":""東京"",""zip"":""100-0001""}}","[""premium"",""vip""]"JavaScript配列内のダブルクォートも、オブジェクト内のネストしたダブルクォートも、全て同じように二重化されています。
よくある間違いと正しい記述例
よくある間違いを3つ紹介します:
# 間違い1:JSON文字列が囲まれていない
1,{"name":"田中","age":30}
# 間違い2:JSONのエスケープ方法(バックスラッシュ)を使っている
1,"{\"name\":\"田中\",\"age\":30}"
# 間違い3:改行文字がそのまま残っている
1,"{""name"":""田中"",
""age"":30}"
# 正しい記述
1,"{""name"":""田中"",""age"":30}"JavaScript間違い1と2は、セクション3で説明した通り、JSON文字列全体をダブルクォートで囲み、内部のダブルクォートを二重化する必要があります。
間違い3の改行文字については、JSON内に改行文字(\n)やタブ文字(\t)が含まれている場合、そのままCSVに書き込むとエラーになるため、削除するか、\\nや\\tといったエスケープシーケンスに置換する必要があります。
まとめ:CSVダブルクォートエスケープのチェックポイント
CSVファイル中でのダブルクォーテーションのエスケープでお困りの皆さんのために、最後にチェックポイントをまとめておきますね!
- フィールド内のダブルクォートは二重化("")する
- CSV標準(RFC4180)に従って、
""で表現する - JSONのエスケープ方法(
\")は使えない
- CSV標準(RFC4180)に従って、
- カンマや改行を含むフィールドは全体をダブルクォートで囲む
- JSON文字列をCSVに変換する場合は必須
- 囲んだ後、内部のダブルクォートは全て二重化する
- 改行・タブ文字を事前に処理する
- 改行文字が含まれている場合は削除またはエスケープする
この3つのポイントを押さえておけば、CSVでのダブルクォーテーションエスケープで悩むことはかなり減ると思います。同じような問題で困っている方の参考になれば嬉しいです!