CSV 書き出しの際に必要なエスケープ処理と二次元配列→文字列変換の方法
こんにちは、ndj です。
二次元配列から変換した CSV
(カンマと改行コードで区切ってあるアレです)をファイルなどに書き出す際に値にエスケープ処理を施す必要があったので、そのときの方法を記録しておきます。
また、合わせて二次元配列を CSV
形式の文字列へ変換する方法についても記録しておきます。
なぜエスケープ処理が必要なのか
CSV
形式のファイルを作成する際、なぜエスケープ処理が必要なのかといいますと、値の中に**,(カンマ)や\n**(改行)が含まれてしまっていると、Excel
や他のアプリケーションなんかで CSV
を読み込んだときに値中に含まれている**,(カンマ)や\n**(改行)と区切り文字である**,(カンマ)や\n**(改行)を区別できないわけです。
なので、値は「""(ダブルクォーテーション)」で囲んで値であるということを明示する必要があります。
エスケープ処理を行う方法
// エスケープ処理
const escapeForCSV = (s) => {
return `"${s.replace(/\"/g, '\"\"')}"`
}
正規表現を用いて、引数として与えられた文字列をダブルクォーテーションで囲っています。
引数として与えられた文字列中に、「"」が含まれていると CSV
に変換した際に値がずれてしまうため、「""」としてエスケープします。
二次元配列から CSV 文字列へ変換する方法
const arrToString = (arr, colDelimeter=',', rowDelimeter='\n') => {
return arr.map((row) => row.map((cell) => escapeForCSV(cell)).join(colDelimeter)).join(rowDelimeter);
}
まず、二次元配列を map()
メソッドで行(row
)を取り出す。
row
は一次元配列になっているので、さらに map()
メソッドを用いてセル(cell
)を取り出す。
このとき、各値にエスケープ処理を施す。
そして、row
を区切り文字で連結(この場合は「,」)する。
最後に行区切り(この場合の区切り文字は「\n」)を行い、完了。
サンプルコード
先述したように、arrToString()
内で各セルに対して escapeForCSV()
を実行して、エスケープ処理を施しています。
TSV
形式にしたい場合は、arrToString()
に引数を渡せばOK。
// エスケープ処理
const escapeForCSV = (s) => {
return `"${s.replace(/\"/g, '\"\"')}"`
}
//二次元配列 -> CSV形式の文字列に変換
const arrToString = (arr, colDelimeter=',', rowDelimeter = '\n') => {
return arr.map((row) => row.map((cell) => escapeForCSV(cell)).join(colDelimeter)).join(rowDelimeter);
}
// CSV 形式文字列に変換
let sample = [['a', 'b', 'c'], ['"a"', '"b"', '"c"']];
console.log(arrToString(sample));
// "a","b","c"
// """a""","""b""","""c"""
// TSV 形式にしたい場合
console.log(arrToString(sample, colDelimeter='\t'));
// "a" "b" "c"
// """a""" """b""" """c"""
最後に
どちらも汎用的な処理なので、おそらくライブラリがあると思いますが、手法を知っておくのは必要だと思ったので、残しておきます。
誤字脱字やアドバイス、ご指摘などございましたらコメントや編集リクエストなどくださると幸いです。
以上です。
ここまで読んでくださりありがとうございました。
参考
CSV について
正規表現について
Qiita: JavaScript 正規表現まとめ @iLLviA 様
非常に参考になりました。ありがとうございました。