LoginSignup
14
17

More than 5 years have passed since last update.

【JavaScript】Excelで読み込んだデータを文字化けさせずにCSVで書き出す

Posted at

Excelからデータを読み込んで処理を行い、
結果をCSVファイルに書き出してExcelで開くといった要件を満たす必要がありました。

しかし、CSVファイルをExcelで開く際は出力時に文字コードをShift-JISにしないと文字化けが起こります。
(ファイル読み込み時にUTF-8を指定できますが、都度操作する必要があります。)

参考:Microsoft Excel で開ける CSV 関連のフォーマットまとめ

今回は、文字化けしないようにCSVファイルをShift-JISで出力し
Excelでスムーズに開けるようにする方法を共有します。

必要なモジュール


const fs = require('fs')
const csv = require('fast-csv')
const jconv = require( 'jconv' )
const xlsx = require('xlsx')
const utils = xlsx.util

Excelデータ読み込み

Excel内のデータを読み込みます。
読み込んだデータはCSV形式のままだと扱い難いのでお好みで配列にしてください。


// csv -> Array[Object]
function parseCSVtoArray(csv) {
  let result = []
  csv
    .fromString(csv, {headers: true})
    .on('data', function(data) {
      result.push(data)
    })
    .on('end', function() {
      console.log('end')
    })
  return result
}

var workbook = xlsx.readFile(importPath) // Excelファイルを読み込む
var sheetName = workbook.SheetNames[0] // Excelファイルの最初のシートの名前を取得
var worksheet = workbook.Sheets[sheetName] // Excelファイルの最初のシートを読み込む

var csv = xlsx.utils.sheet_to_csv(worksheet) // ExcelデータをCSV形式で取得
let array = yield parseCSVtoArray(csv) // データを使いやすくするために配列に変換

for (let arr of array ) {
  console.log(arr['hoge'])

  // 処理 …
}

CSV書き出し

jconv を使って処理結果をShift-JISに変換します。

ここでは処理結果を配列で拾っているので、
ヘッダーを付けてCSV(文字列)に変換したものを渡しています。

Bufferについてはこちらを参考にしてください。

// resultArray: 処理結果が入った配列

// Array[object] -> csv
csv.writeToString(resultArray, {headers: true}, (err, data) => {

  var buffer = jconv.convert(data, 'UTF8', 'SJIS') // UTF-8からShift-JISへ文字コードを変換
  fs.writeFileSync('result.csv', buffer) // ファイルを書き出し
})

これで文字コードがShift-JISのCSVファイルが書き出されたので、
Excelで開いてもウィザード無しで文字化けもせずスムーズに開けます。

おまけ:Excelデータで書き出し

このデータをExcelで書き出したい場合は、node-xlsxを使うと簡単に出力できます。


const nodeXlsx = require('node-xlsx').default


function convertCSVtoArray(str) {
  var result = []
  var tmp = str.split('\n')

  for(var i = 0; i < tmp.length; ++i) {
    result[i] = tmp[i].split(/(?:",|,"|,(?=(?:(?:[^\"]*\"){2})*[^\"]*$))/) // ※セル内の複数値に対応 
  }
  return result
}

csv.writeToString(resultArray, {headers: true}, (err, data) => {

  var arr = convertCSVtoArray(data)
  var buffer = nodeXlsx.build([{name: sheetName, data: arr}])
  fs.writeFileSync('result.xlsx', buffer)
})

これで .xlsx ファイルで書き出されます。

ヘッダーを意識せずに付加する為に一度csvにしてからまた配列に戻す手間をしてますが、
必要がない場合や別途加工する場合は writeToString を挟む必要は無いと思います。

終わりに

完全にモジュール頼りですが、これらの素晴らしいモジュールを知って
Excelで消耗する人が一人でも減ってくれれば嬉しいです。

参考

14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17