CSV を扱うツールを作っていると、かなりの頻度でぶつかるのが文字コードの問題です。
「UTF-8 の CSV を Excel で開いたら文字化けした」
「取引先から送られてきた Shift_JIS の CSV をシステムに入れたら壊れた」
このあたりは日本語の実務だと本当によくあります。
そこで今回は、ぱんだツールズ の CSV文字コード変換ツール を題材に、ブラウザ内でどう動いているのか を整理してみます。
やること自体は単純で、流れとしては次の 3 段階です。
- CSV ファイルをバイト列として読む
- そのバイト列がどの文字コードかを判定、または指定してデコードする
- 目的の文字コードで再エンコードしてダウンロードさせる
仕組みを分解すると、意外と難しくありません。
そもそも何が問題なのか。CSVは見た目が同じでも中身のバイト列が違う
CSV はただのテキストファイルですが、同じ「あいうえお」と表示されていても、内部のバイト列は文字コードによって変わります。
例えば代表的なものはこのあたりです。
- UTF-8
- Shift_JIS
- EUC-JP
- UTF-16
Web 開発では UTF-8 前提で進むことが多いですが、日本の業務フローでは今でも Shift_JIS の CSV がかなり残っています。
そのため、単に FileReader で文字列として読めばよいわけではありません。
まずは ファイルを生のバイト列として扱う 必要があります。
基本の流れ。最初に文字列ではなく ArrayBuffer として読む
ブラウザで CSV を受け取る場合、input type="file" かドラッグ&ドロップで File オブジェクトを取得します。
ここで最初からテキストとして読むと、文字コードの解釈をブラウザ任せにしてしまうので危険です。
まずはこういう流れで、ArrayBuffer として読みます。
async function readFileAsBytes(file: File): Promise<Uint8Array> {
const buffer = await file.arrayBuffer();
return new Uint8Array(buffer);
}
この段階では、まだ「文字」ではなく単なるバイト列です。
例えば Shift_JIS の CSV なら、日本語 1 文字が 1 バイトまたは 2 バイトで表現されます。
UTF-8 なら 1 文字あたりのバイト数は別のルールになります。
つまり、まず必要なのは「このバイト列をどのルールで文字に戻すか」を決めることです。
文字コード変換ツールの肝。デコードとエンコードを分けて考える
文字コード変換は、頭の中で次の 2 ステップに分けると整理しやすいです。
- バイト列を文字列に戻す
- 文字列を別の文字コードのバイト列に変換する
前半を デコード、後半を エンコード と考えます。
たとえば Shift_JIS の CSV を UTF-8 に変換するなら、
- Shift_JIS のバイト列を Unicode 文字列として解釈する
- その Unicode 文字列を UTF-8 のバイト列に変換する
という流れです。
この「いったん内部では文字列に戻す」という段階を挟むのがポイントです。
判定はどうやるのか。自動判定は万能ではない
実装上は「文字コードを自動判定したい」と考えがちですが、ここは少し注意が必要です。
文字コードの自動判定は、厳密にはかなり難しいです。
特に短い CSV や、数字・ASCII 文字が多い CSV は判定材料が少なくなります。
例えば次のようなファイルは判定が難しくなります。
- ヘッダーが英数字だけ
- 中身が日付や数値中心
- 日本語が数行しか入っていない
なので実務向けのツールでは、だいたい次のどちらかにします。
- BOM やバイトパターンを見て自動推定する
- ユーザーに元の文字コードを選ばせる
実際には、自動推定を補助として使いつつ、最終的には選択肢を出す ほうが安全です。
ブラウザ実装でよくある構成。encoding-japaneseのようなライブラリを使う
JavaScript 標準の TextDecoder / TextEncoder でも UTF 系の処理はやれますが、Shift_JIS を含む日本語の実務向け変換では対応が足りないことがあります。
そのため、ブラウザ完結で作るなら encoding-japanese のようなライブラリを使う構成が実用的です。
イメージとしては次のような流れです。
import Encoding from "encoding-japanese";
function decodeCsv(bytes: Uint8Array, from: Encoding.Encoding): string {
const unicodeArray = Encoding.convert(bytes, {
to: "UNICODE",
from,
type: "array",
});
return Encoding.codeToString(unicodeArray);
}
function encodeCsv(text: string, to: Encoding.Encoding): Uint8Array {
const unicodeArray = Encoding.stringToCode(text);
return new Uint8Array(
Encoding.convert(unicodeArray, {
to,
from: "UNICODE",
type: "array",
})
);
}
やっていることはシンプルで、
- 入力ファイルのバイト列を Unicode 文字列に戻す
- その文字列を目的の文字コードへ変換する
だけです。
見た目には「CSV を変換している」ように見えますが、実際に変換しているのは CSV の構造そのものではなくテキストのエンコーディング です。
CSVツールとしては、区切り文字や改行コードも一緒に面倒を見ると使いやすい
厳密には文字コード変換だけでもツールとして成立します。
ただ、実際の運用では次も同時に問題になることが多いです。
- カンマ区切りではなくタブ区切りになっている
- 改行コードが
LFとCRLFで食い違う - ダブルクオートを含むセルの扱いが壊れる
なので、実務で使いやすいツールにするなら、
- 文字コード変換
- 改行コード変換
- CSV パースと再生成
を分けて考えるのが大事です。
単にバイト列を文字列へ戻して再エンコードするだけなら高速ですが、列の整形や値の検査までやるなら Papa Parse のような CSV パーサーも併用することになります。
ダウンロードはどうやるのか。Blob を作ってその場で保存させる
変換後のデータは、ブラウザ上で Blob にしてダウンロードさせるのが一般的です。
function downloadBytes(bytes: Uint8Array, filename: string) {
const blob = new Blob([bytes], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
これならサーバーにファイルを送らず、そのままローカルで完結できます。
業務ファイルを扱うツールでは、この「アップロードしなくてよい」はかなり大きな価値があります。
ブラウザ完結にするメリット。プライバシーと運用コストの両方に効く
CSV の文字コード変換は、サーバー側でやることももちろんできます。
ただ、ブラウザ内で完結させると次の利点があります。
- 機密データを外部へ送らずに済む
- 小さな変換なら体感が速い
- サーバー負荷と保存リスクを減らせる
- 個人開発でも運用コストを抑えやすい
特に CSV は顧客情報や請求データを含むことが多いので、「変換のために外部アップロードが必要です」は思った以上に心理的ハードルがあります。
実装でハマりやすいポイント
最後に、文字コード変換ツールを作るときにハマりやすい点を挙げます。
1. UTF-8 with BOM をどう扱うか
Excel 向けでは、UTF-8 でも BOM 付きのほうが都合がよいことがあります。
そのため「UTF-8 に変換」で終わりではなく、
- UTF-8
- UTF-8 with BOM
を分けて出せるようにすると実務では親切です。
2. 文字化けした後のファイルは元に戻せないことがある
一度誤った文字コードで保存し直された CSV は、元の情報が壊れていることがあります。
つまり、変換ツールで救えるのは 元データのバイト列がまだ正しい場合 です。
すでに壊れた文字列を再変換しても完全には戻らないケースがあります。
3. 巨大ファイルはブラウザメモリを圧迫する
ブラウザ完結は便利ですが、数百 MB 級の CSV を読むとメモリ使用量が増えます。
小中規模の実務ファイルなら十分実用的ですが、巨大データ向けにはストリーム処理やサーバー処理を検討したほうがよいです。
まとめ
CSV文字コード変換ツールの中身は、突き詰めると次の流れです。
- ファイルを
ArrayBufferとして読む - 元の文字コードでデコードする
- 目的の文字コードでエンコードする
-
Blobとしてダウンロードさせる
派手さはありませんが、日本語の実務ではかなり価値のあるツールです。
特に Shift_JIS と UTF-8 の行き来は、いまでも現場で普通に発生します。
もしブラウザ完結の小さな業務ツールを作ってみたいなら、CSV 文字コード変換はかなり良い題材だと思います。
実際に試したい場合は、こちらから使えます。
ぱんだツールズ では他にも PDF・画像・CSV・テキスト処理などの開発者向けツールを 50 個以上公開しています。全部無料・登録不要・ブラウザ完結で使えます。
https://sakutto-panda.com
この記事は Zenn にも同じ内容を投稿しています。