[React / JavaScript] ExcelJSで実装したCSV出力機能でSJIS変換対応をしてみた

2021.08.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

前回のエントリでは、ExcelJSを使用してアプリにExcel/CSVのダウンロード機能を実装しましたが、その際のCSVの文字コードはUTF8でした。

今回は、ReactアプリでExcelJSで実装したCSV出力機能で文字コードをSJIS(Shift-JIS)に変換する対応をしてみました。

デモ

下記リンクを別タブで開きます。上記サンドボックスのプレビューが開けます。

SJIS形式でダウンロード

[CSV形式(SJIS)]をクリックして、ファイルをダウンロードします。

ダウンロードしたファイルをVSCodeで開くと、日本語文字(ダブルバイト文字)が文字化けします。

[UTF-8]をクリックして、[Reopen with Encoding]をクリックします。

[Japanese (Shift JIS)]をクリックしてファイルをSJISで開き直します。

すると文字化けが解消して日本語文字が正常に表示されました。

ファイルをExcelで開いても文字化けなく日本語文字を表示させられました。

UTF8形式でダウンロード

UTF8の方も試してみます。

[CSV形式(UTF8)]をクリックして、ファイルをダウンロードします。

ダウンロードしたファイルをVSCodeで開くと、UTF8で文字化けなく開けました。

ファイルをExcelで開くとこちらはちゃんと(?)文字化けしました。

コード概要

src/App.tsx

import React from "react";
import "./styles.css";
import ExcelJS from "exceljs";
import encoding from "encoding-japanese";

export const App: React.FC = () => {
  const handlerClickDownloadButton = async (
    e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
    format: "xlsx" | "csv",
    charcode?: "UTF8" | "SJIS"
  ) => {
    e.preventDefault();

    const workbook = new ExcelJS.Workbook();
    workbook.addWorksheet("sheet1");
    const worksheet = workbook.getWorksheet("sheet1");

    worksheet.columns = [
      { header: "ID", key: "id" },
      { header: "作成日時", key: "createdAt" },
      { header: "名前", key: "name" }
    ];

    worksheet.addRows([
      {
        id: "f001",
        createdAt: 1629902208,
        name: "りんご"
      },
      {
        id: "f002",
        createdAt: 1629902245,
        name: "ぶどう"
      },
      {
        id: "f003",
        createdAt: 1629902265,
        name: "ばなな"
      }
    ]);

    const uint8Array =
      format === "xlsx"
        ? await workbook.xlsx.writeBuffer()
        : charcode === "UTF8"
        ? await workbook.csv.writeBuffer()
        : new Uint8Array(
            encoding.convert(await workbook.csv.writeBuffer(), {
              from: "UTF8",
              to: "SJIS"
            })
          );
    const blob = new Blob([uint8Array], {
      type: "application/octet-binary"
    });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "sampleData." + format;
    a.click();
    a.remove();
  };
  return (
    <>
      <header>
        <h1>データ出力</h1>
      </header>
      <>
        <button onClick={(e) => handlerClickDownloadButton(e, "xlsx")}>
          Excel形式
        </button>
        <button onClick={(e) => handlerClickDownloadButton(e, "csv", "UTF8")}>
          CSV形式(UTF8)
        </button>
        <button onClick={(e) => handlerClickDownloadButton(e, "csv", "SJIS")}>
          CSV形式(SJIS)
        </button>
      </>
    </>
  );
};
  • 文字コードの変換にはencoding-japaneseを使用しています。
  • await workbook.csv.writeBuffer()により作成したuint8ArrayはUTF8となります。「CSV形式(SJIS)」ボタンが押された時はそれをencoding.convert()によりUTF8からSJISに変換して新しいuint8Arrayを作成しています。

参考

以上