本文へ移動
Base64
UTF-8・URL-safe の変換はサンプルや機密情報を含まない値で。
ブログ

Base64の日本語: UTF-8かShift_JISか

UTF-8とShift_JISを区別。失われたバイトはBase64で復元できません。

公開サンプルで確認 →
この記事のポイント3つ

訂正 · 2026年10月10日: 復元の条件を修正。

  1. ①
    先にUTF-8へ 先にUTF-8バイトへ変換。
  2. ②
    Shift_JISは別に確認 送り手に文字コードを確認。
  3. ③
    欠損は復元できない 失ったバイトは戻せません。
AI 生成の概念画像: 布の上の紙に btoa が日本語で止まる、InvalidCharacterError と書かれ、万年筆と茶器が置かれています。実際のエラー画面ではありません。

btoa('日本語')で止まる場合と、受け取ったBase64を開いても読めない場合は別の問題です。まず「Base64の構文」「元の文字コード」「元のバイトが残っているか」を分けて確認してください。このページのBase64ツールはUTF-8テキスト用です。

訂正 — 2026年10月10日: 以前の「同じ値をUTF-8で読めば日本語が戻る」という説明は条件が不足していました。既知のShift_JIS例、復元できない条件、ASCIIとLatin-1の違い、利用先のパディング条件を追加しました。古い変換・URL-safeカードは記事から外しました。表紙はAI生成の概念画像であり、実際のエラー画面や動作記録ではありません。

受け取った日本語が読めないときの確認順

現象まず確認すること次の行動
btoa('日本語')がエラー文字列をバイトに変えたかTextEncoderでUTF-8にしてからBase64へ
atobの結果が日本語に見えない送り手の文字コード元のバイトを、確認済みの文字コードで読む
Base64の構文エラーコピー時の欠落、不要な文字、パディング元の値と利用先の形式を照合する
構文は通るがUTF-8エラー別の文字コードか、画像・圧縮ファイルか送り手に形式を確認。ファイルには専用ツールを使う
途中で切れた、�に置き換えた後に保存した変更前のデータが残っているか原文・元のバイトを再取得する

元のバイトが失われた場合、Base64を繰り返しても消えた内容は分かりません。�という文字が元の文章に含まれる場合もあるので、見た目だけで破損と断定しないでください。

送り手に聞くなら「文字コードはUTF-8ですか、Shift_JISですか」「文字列ではなく画像などのファイルですか」「変換前のバイトや欠けていない値がありますか」の3点から始められます。エラーが出ないだけでは、指定した文字コードが正しい証拠にはなりません。

同じ「日本語」でも、バイトが違う

次は機密情報を含まない固定サンプルです。ツールでデコードを選び、1行ずつ試してください。結果はこのページのUTF-8専用ツールに対するものです。

元の形式貼り付けるBase64このツールでの結果
ASCIIのHelloSGVsbG8=Hello
UTF-8の日本語5pel5pys6Kqe日本語
既知のShift_JISバイトの日本語k/qWe4zqUTF-8エラー。結果のコピーは無効
btoa('café')の1バイト経路Y2Fm6Q==UTF-8エラー。結果のコピーは無効
UTF-8のcaféY2Fmw6k=café
UTF-8のこんにちは 🌏44GT44KT44Gr44Gh44GvIPCfjI8=こんにちは 🌏

文字コードを自動判定しません。 Shift_JISの行は、本文で用意した93 fa 96 7b 8c eaという6バイトに対応します。UTF-8用ツールがエラーを出すことは、Base64そのものが壊れている証拠ではありません。一方、読めそうな結果が出るまで文字コードを次々変える方法でも、元の形式は確定できません。

btoaにはUnicode文字列ではなくバイト相当の値を渡す

btoaの仕様説明では、各値を0〜255のバイトとして扱います。あはU+3042で範囲外なので直接渡すとInvalidCharacterErrorになります。通常の日本語や絵文字は先にUTF-8バイトへ変換します。

ASCIIのHelloなら直接経路とUTF-8経路が一致します。しかしLatin-1範囲のcaféは直接渡せてもY2Fm6Q==になり、UTF-8経由のY2Fmw6k=とは違います。「btoaがエラーを出さない」ことと「UTF-8でエンコードした」ことは同じではありません。

以下は短い公開サンプル専用のブラウザーコードです。ファイル・巨大データ・不正なUTF-16入力の一般処理ではありません。

const text = 'こんにちは 🌏';
const bytes = new TextEncoder().encode(text);
let binary = '';
for (const byte of bytes) binary += String.fromCharCode(byte);
const base64 = btoa(binary);
const restoredBytes = Uint8Array.from(atob(base64), ch => ch.charCodeAt(0));
const restored = new TextDecoder('utf-8', {
  fatal: true, ignoreBOM: true
}).decode(restoredBytes);
console.log({ base64, restored, byteLength: bytes.length });

出力のBase64は44GT44KT44Gr44Gh44GvIPCfjI8=、戻る文字列はこんにちは 🌏、UTF-8の長さは20バイトです。atobはバイト相当の文字列を返すので、そのまま日本語として表示するのではなくバイト配列に戻して読みます。

fatal: trueは不正なバイトを黙って置換せずエラーにします。ignoreBOM: trueは先頭のBOM(U+FEFF)を結果に含める指定です。「BOMを削除する」という意味ではありません。このツールもBOMを保持し、見えない文字を含む場合は注意を表示します。

Shift_JISだと確認できている場合の独立サンプル

Encoding StandardにはUTF-8以外のデコーダーも定義されています。次は送り手が文字コードを確認済みという前提で、この固定サンプルだけを比較するコードです。

const knownShiftJisBase64 = 'k/qWe4zq';
const bytes = Uint8Array.from(atob(knownShiftJisBase64), ch => ch.charCodeAt(0));
let utf8Result;
try {
  utf8Result = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
} catch {
  utf8Result = 'UTF-8 error';
}
const shiftJisText = new TextDecoder('shift_jis', { fatal: true }).decode(bytes);
console.log({ utf8Result, shiftJisText });

このサンプルではUTF-8側がUTF-8 error、Shift_JIS側が日本語です。PiPiのツールにShift_JIS 対応を追加したわけではありません。 未知の値の文字コードを推測する機能でも、失われた原文を直す機能でもありません。実データは所属組織で承認されたローカル手順と、送り手の形式情報で扱ってください。

URL-safeとサイズは、文字コードとは別に確認

RFC 4648のbase64urlは、標準の+・/を-・_に変えるアルファベットです。パディング省略は利用先の規則に従います。PiPiのURL-safeエンコードは末尾の=を省略するため、上の例は44GT44KT44Gr44Gh44GvIPCfjI8になります。ほかのAPIにも同じ規則があるとは限りません。

改行なし・パディングありの標準Base64の長さは4 × ceil(入力バイト数 / 3)文字です。日本語は9バイト → 12文字、こんにちは 🌏は20バイト → 28文字、Helloは5バイトから8文字になります。画面の日本語の文字数をそのまま計算に使わず、短い入力まで「必ず約33%増」と考えないでください。

本番の秘密は貼り付けない

Base64は暗号化ではありません。本番トークン・パスワード・非公開データは入力しないでください。変換自体がブラウザ内で動くことは、ページ全体やブラウザー環境で秘密が守られる保証ではありません。

JWTの構造を読むJWTデコーダーも、署名の検証や信頼性の判定ではありません。URLで送る文字の扱いはURLエンコードツールで別に確認できます。まずは上の公開サンプルで期待結果を照合し、自分の値については送り手の文字コード・形式・完全性を確かめてください。

よくある質問

btoaに日本語を渡すとなぜエラーになりますか?
btoaは文字列の各値を0〜255のバイトとして扱います。あ(U+3042)は範囲外なのでInvalidCharacterErrorになります。通常のUnicode文字列はTextEncoderでUTF-8バイトにしてからエンコードしてください。
UTF-8でデコードすれば日本語は必ず戻りますか?
いいえ。元のUTF-8バイトが残っていて誤った文字コードで読んだだけなら、正しく読み直せます。Shift_JISなどの別形式やファイルはUTF-8では読めない場合があります。切れた値や失われた元のバイトはBase64だけで復元できません。
このツールでShift_JISをデコードできますか?
できません。このツールはUTF-8テキスト用で、文字コードを自動判定しません。送り手に文字コードと元のバイトを確認してください。本文のShift_JIS例は確認済みの公開バイトを独立したコードで読む説明であり、ツールに機能を追加したものではありません。
URL-safeなら末尾の=を消してよいですか?
利用先の規則次第です。base64urlのアルファベットは+と/を-と_に変えますが、パディング省略は別条件です。PiPiのURL-safe出力は=を省略します。ほかのAPIでも省略できるとは限りません。
Base64の長さは何を基準に計算しますか?
画面の文字数ではなく入力バイト数です。改行なし・パディングありの標準Base64は4 × ceil(入力バイト数 / 3)文字になります。文字列「日本語」はUTF-8で9バイト、Base64で12文字です。短い入力の増加率は約33%を超える場合があります。
入力した値は安全ですか?
変換処理自体はブラウザ内で実行します。それだけではサイト全体やブラウザ環境で秘密情報が安全だとは言えません。本番トークン・パスワード・非公開データは入力せず、公開サンプルか機密情報を含まないテスト値で確認してください。

出典

確認記録: Codex AI editorial/code audit (not a human specialist review)

確認内容と限界を開く

2026-10-10 KSTに日本語の運営ツールへ公開UTF-8・既知Shift_JIS・Latin-1・絵文字の値を入力し、正しい結果またはUTF-8エラーとコピー無効を確認しました。MDN btoa・TextDecoder、WHATWG Encoding Standard、RFC4648を照合し、本文の2コードをそのまま実行する回帰テストで検算します。Nativeプレビューと運営配信の検査結果は別のrelease receiptsで確認し、読者・収益や人による専門監査とは扱いません。再読していないRFC6750のアクセス日は保持します。

この記事で加えたこと — 同じ日本語をUTF-8と既知のShift_JISバイトに分けて検算し、日本語の受信データで起きる構文・文字コード・欠損の問題を切り分けます。実際のUTF-8ツールの拒否条件と、本文の独立した既知文字コードサンプルを区別します。

確認記録は記載された確認内容であり、独立した正確性の保証ではありません。

ツールに戻る →