結論

文字コードは「文字に割り当てた番号(Unicode なら「あ」は U+3042)」と「その番号をバイトにする方式(UTF-8 なら E3 81 82、Shift_JIS なら 82 A0)」の組み合わせです。下のツールに文字を入れると、Unicode・UTF-8・Shift_JIS・UTF-16・\u・文字参照を一度に表示し、コードやバイトから文字にも戻せます。

この記事でわかること

  • 文字コード表の読み方と、UTF-8・UTF-16・Shift_JIS・ASCII の決まり
  • Python・Java・JavaScript・PHP・Go・iconv・nkf で同じ文字を変換した出力
  • ~・〜・①・髙が Shift_JIS と CP932 と実装ごとに分かれる実測

2026年11月10日更新|Python 3.13・Node.js 22・Java 21・iconv・nkf・Chromium で実行確認

文字コード調べを読み込み中です。

ツールの使い方:上の切り替えで3つの使い方を選べます。

  • 文字 → コード:調べたい文字を入れると、1文字ずつ(先頭30文字まで)Unicode(U+)・10進数・UTF-8 のバイトとバイト数・Shift_JIS のバイト(無い文字は「なし」)・UTF-16(絵文字はサロゲートペアと表示)・JavaScript/Java/JSON の \u・Python の \u/\U・HTML の文字参照(&#x; と &#;)・CSS の \ を表で出します。空白・全角空白・NBSP・BOM・ゼロ幅スペース・制御文字は名前で示すので、見えない文字が混ざっていないかも分かります。
  • コード → 文字:U+3042・\u3042・\u{1F600}・\U0001F600・あ・あ・0x41 を文字に戻します(\uD83D\uDE00 のようなサロゲートペアも1文字にします)。空白区切りの16進バイト(E3 81 82)・\xE3・%E3 の形は UTF-8 と Shift_JIS の両方で読みます。数字だけ(3042)は16進と10進の両方を出します。
  • ASCII コード表:0〜127 を10進と16進で並べ、制御文字は名前(LF・CR など)で示します。

Shift_JIS は、ブラウザが持つ WHATWG の変換表(Windows の CP932 とほぼ同じ)で調べます。入力した内容はどこにも送信されません。

この記事で実際に動かしたもの:上のツール(Chromium)、Python・Node.js・Java・PHP・Go のプログラム、iconv・nkf・file・xxd・od のコマンド、Shift_JIS のページからのフォーム送信。

flowchart TD
    A[文字 あ] -->|文字集合 Unicode| B[コードポイント U+3042]
    B -->|UTF-8| C[E3 81 82]
    B -->|UTF-16| D[30 42]
    A -->|文字集合 JIS X 0208| E[区点 4区2点]
    E -->|Shift_JIS| F[82 A0]

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
文字コードとは 文字に番号を付ける表(文字集合)と、番号をバイトにする方式(符号化)の組み合わせ 文字コードとは
「あ」の文字コード Unicode は U+3042(10進 12354)、UTF-8 は E3 81 82、Shift_JIS は 82 A0 文字コード表の読み方
UTF-8 は何バイト 英数字1・ラテン文字の多く2・ひらがなと漢字の多く3・絵文字4バイト UTF-8とは
Unicode 変換(\u3042 を文字に) 上のツールの「コード → 文字」。Python なら chr(0x3042) 言語別の文字コード変換
ASCII コード表 0〜127。A は 65(0x41)、a は 97(0x61)、改行 LF は 10 ASCIIコード表
Shift_JIS と CP932 の違い CP932 は ①・髙 などを足した Windows の版。~ の扱いも違う Shift_JISとCP932の違い
ファイルの文字コードを調べる nkf --guess・file。短いファイルは外れることがある コマンドで文字コードを調べる
文字化けを直したい 化けた文字の形で、どの組み合わせで読んだかが分かる 文字化けの仕組み

確認環境:Ubuntu 24.04.5 LTS の上で、Python 3.13.18(unicodedata は Unicode 15.1.0)、Node.js 22.23.4(ICU 78.3)、OpenJDK 21.0.12.1、PHP 8.3.6、Go 1.24.7、glibc 2.39 の iconv、nkf 2.1.5 と xxd(Ubuntu の .deb を作業場所に展開して使用)、file 5.45、GNU coreutils の od で、同じ文字を変換した出力を取りました。記事内ツールの表示と、Shift_JIS のページからフォームを送ったときのバイトは、Chromium 153.0.8010.12(playwright 1.63.0、127.0.0.1 の自分のページ)で確かめています。UTF-8・UTF-16 の決まりは RFC 3629・RFC 2781、ブラウザの Shift_JIS は WHATWG Encoding Standard、Java の文字コード名は Oracle の公式ドキュメント、Windows のコードページ番号は Microsoft Learn で確かめました。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年11月9日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「文字コード表・変換ツール|Unicode・UTF-8・Shift_JISの調べ方」

文字コードとは(文字集合と符号化の違い)

この節では、「文字コード」という言葉が指す2つのものと、Unicode と UTF-8 の関係が分かります。

コンピューターは文字をそのまま覚えられないので、文字ごとに番号を決め、その番号をバイト(8ビットの数)の並びにして保存します。この「番号の表」と「バイトにする方式」をまとめて文字コードと呼びます。

文字集合(どの文字に何番を付けるか)

Unicode:世界の文字に U+0000〜U+10FFFF の番号を付ける

JIS X 0208:日本の漢字・かなに「区」と「点」の番号を付ける

ASCII:英数字と記号・制御文字に 0〜127 を付ける

符号化方式(番号をどうバイトにするか)

UTF-8・UTF-16・UTF-32:Unicode の番号をバイトにする

Shift_JIS・EUC-JP・ISO-2022-JP:JIS の番号をバイトにする

ASCII は番号がそのまま1バイトになる

「Unicode と UTF-8 の違い」はここにあります。Unicode は番号の表、UTF-8 はその番号をバイトにする方式の1つです。同じ U+3042 でも、UTF-8 なら3バイト(E3 81 82)、UTF-16 なら2バイト(30 42)になります。一方、Shift_JIS は Unicode とは別の表(JIS X 0208 など)を使う方式で、「あ」は 82 A0 です。

ファイルを開く側が、保存した側と違う方式でバイトを読むと、別の文字に見えます。これが文字化けです。文字コードを調べるときは、「どの文字集合の何番か」と「どの方式で何バイトか」を分けて見ると、迷いにくくなります。

文字コード 文字集合 1文字のバイト数 主な使われ方
ASCII ASCII(128文字) 1 英数字だけのデータ、各方式の土台
UTF-8 Unicode 1〜4 Web・Linux・macOS・ソースコード・JSON
UTF-16 Unicode 2 または 4 Java・JavaScript・Windows の内部の文字列
UTF-32 Unicode 4 番号をそのまま並べたいときの内部処理
Shift_JIS/CP932 JIS X 0201・JIS X 0208(CP932 は拡張つき) 1 または 2 以前の Windows の日本語ファイル、Excel の CSV
EUC-JP JIS X 0208 など 1〜3 以前の Unix・Linux の日本語ファイル
ISO-2022-JP(JIS) JIS X 0208 など エスケープで切り替え 以前の日本語の電子メール

Python で同じ文「文字コードはUTF-8に」を各方式でバイトにすると、UTF-8 は26バイト、UTF-16 は24バイト、UTF-32 は48バイト、CP932・EUC-JP は19バイト、ISO-2022-JP は切り替えの3バイトが入って31バイトでした。日本語が多い文は UTF-8 のほうが大きくなりますが、どの言語の文字も1つの方式で扱えることを優先して、今は UTF-8 が標準になっています。

文字コード表の読み方(「あ」は U+3042)

この節では、文字コード表に並ぶ U+3042・12354・E3 81 82・\u3042・あ がどれも同じ「あ」を指す理由と、その読み方が分かります。

表記は違っても、元は1つの番号です。Unicode の番号 0x3042(16進)は10進で 12354 です。これを書く場所ごとの決まりで書いたものが、次の表の各行です。上のツールの「文字 → コード」で「あ」を入れたときの表示と同じ値です。

表記 「あ」の値 どこで使うか
Unicode(コードポイント) U+3042 文字コード表・仕様書。U+ の後ろは16進
10進数 12354 Python の ord()、HTML の あ
UTF-8(バイト) E3 81 82(3バイト) ファイルの中身・通信・URL の %E3%81%82
UTF-16 3042 Java・JavaScript の charCodeAt
Shift_JIS(バイト) 82 A0 Shift_JIS で保存したファイルの中身
JavaScript・Java・JSON \u3042 文字列の中で文字を番号で書く
Python \u3042(5桁以上は \U と8桁) 文字列の中で文字を番号で書く
HTML(文字参照) あ / あ HTML の本文・属性
CSS \3042 content: "\3042"; など

よく使う文字を、Python 3.13 で変換して並べました。「なし」は、その方式では表せない文字です。

文字 Unicode(10進) UTF-8 Shift_JIS EUC-JP
AU+0041(65)414141
あU+3042(12354)E3 81 8282 A0A4 A2
アU+30A2(12450)E3 82 A283 41A5 A2
ア(半角)U+FF71(65393)EF BD B1B18E B1
全角空白U+3000(12288)E3 80 8081 40A1 A1
€U+20AC(8364)E2 82 ACなしなし
😀U+1F600(128512)F0 9F 98 80なしなし
𠮷(つちよし)U+20BB7(134071)F0 A0 AE B7なしなし

半角カナの「ア」は Shift_JIS では1バイト(B1)ですが、UTF-8 では3バイトです。「半角は1バイト」は Shift_JIS の話で、UTF-8 では成り立ちません。全角と半角の変換そのものは、関連記事「全角⇔半角変換の早見表|Java・JS・Python・Excel・SQL」で扱っています。

自分で確かめる(ブラウザで1行)

ブラウザの開発者ツール(F12)のコンソールに次の1行を貼ると、文字の番号と UTF-8 のバイトが出ます。Chromium で実行した結果を下に載せます。

[..."あ😀"].map(c => "U+" + c.codePointAt(0).toString(16).toUpperCase() + " " + [...new TextEncoder().encode(c)].map(b => b.toString(16).toUpperCase()).join(" "))
["U+3042 E3 81 82","U+1F600 F0 9F 98 80"]

UTF-8とは(1〜4バイトの決まり)

この節では、UTF-8 が番号を何バイトにするかの決まりと、先頭のバイトを見ただけで文字の長さが分かる理由が分かります。

UTF-8 は、Unicode の番号の大きさに応じて1〜4バイトを使う方式です。決まりは RFC 3629 にあり、次の表のとおりです。

番号の範囲 バイト数 ビットの形 例
U+0000〜U+007F10xxxxxxxA → 41
U+0080〜U+07FF2110xxxxx 10xxxxxxé → C3 A9
U+0800〜U+FFFF31110xxxx 10xxxxxx 10xxxxxxあ → E3 81 82
U+10000〜U+10FFFF411110xxx 10xxxxxx ×3😀 → F0 9F 98 80

「あ」U+3042 を2進にすると 0011 0000 0100 0010 です。3バイトの形に、上から4ビット・6ビット・6ビットに分けて入れます。

1

16ビットを 4・6・6 に分ける

0011・000001・000010

U+0800〜U+FFFF は3バイト

2

先頭に目印のビットを付ける

1バイト目は 1110、2・3バイト目は 10 を前に付ける:11100011・10000001・10000010

目印で長さが分かる

3

16進に直す

E3 81 82。Python の 'あ'.encode() と同じ値になった

ツールの UTF-8 欄と一致

先頭のバイトを2進で見ると、何バイトの文字かが分かります。Python で各文字の UTF-8 の先頭バイトを出した結果です。

A 1 0b1000001
é 2 0b11000011
あ 3 0b11100011
😀 4 0b11110000
1バイト英数字・記号(ASCII)ASCII のファイルはそのまま UTF-8
3バイトひらがな・カタカナ・多くの漢字全角空白も3バイト
4バイト絵文字・𠮷 などの拡張漢字MySQL は utf8mb4 が要る

10xxxxxx の形のバイトは、文字の途中にしか現れません。そのため、バイトの並びの途中から読んでも次の文字の頭が見つかり、壊れたバイトがあっても被害がその1文字で止まります。一方、続きのバイトが足りない並び(E3 81 だけなど)は UTF-8 として読めず、ツールでは �(U+FFFD、置き換え文字)と表示されます。

BOM(後の節)を付けない UTF-8 を「UTF-8N」と呼ぶことがありますが、これは一部のエディタでの呼び名で、規格の名前ではありません。

UTF-16とサロゲートペア(絵文字の長さが2になる理由)

この節では、JavaScript や Java で絵文字1つの長さが2になる理由と、\uD83D\uDE00 の意味が分かります。

UTF-16 は、U+FFFF までの文字を2バイト1つ、それより大きい文字を2バイト2つ(サロゲートペア)で表す方式です。JavaScript と Java の文字列は内部が UTF-16 なので、length はこの2バイトの単位を数えます。

😀 U+1F600 は次の手順で2つに分かれます(RFC 2781)。0x1F600 から 0x10000 を引いた 0xF600 を20ビットにし、上の10ビット(0x3D)を 0xD800 に、下の10ビット(0x200)を 0xDC00 に足します。結果は D83D DE00 で、上のツールの UTF-16 欄の表示と同じです。

Node.js 22 で確かめた出力です。

length 3 2
charCodeAt [ '3042', 'D83D', 'DE00' ]
codePointAt [ 'U+3042', 'U+1F600' ]
TextEncoder E3 81 82 F0 9F 98 80
あ😀 あ 😀 😀
slice(0,1) "\ud83d"

「あ😀」の length は3、[...s].length(コードポイントの数)は2です。slice(0,1) で絵文字の前半だけを切り出すと、"\ud83d" という片割れが残ります。文字数の制限や切り詰めを length と slice で行うと、絵文字が壊れることがあります。

Java 21 でも同じでした。

length=2 codePointCount=1
charAt(0)=D83D codePointAt(0)=U+1F600

Python 3 の str はコードポイント単位なので、len("😀") は1でした(UTF-16 にしたときの単位の数は2)。Go の len() は UTF-8 のバイト数を返し、「あ😀」は7、utf8.RuneCountInString は2でした。

言語 「あ😀」の長さ 何を数えているか コードポイント数の取り方
JavaScript3UTF-16 の単位[...s].length
Java3UTF-16 の単位s.codePointCount(0, s.length())
Python 32コードポイントlen(s)
Go7UTF-8 のバイトutf8.RuneCountInString(s)
PHP7(strlen)バイトmb_strlen($s) は2

家族の絵文字や肌の色つきの絵文字のように、複数のコードポイントを組み合わせて1つに見える文字もあります。見た目の1文字(書記素クラスタ)を数えるには、JavaScript なら Intl.Segmenter を使います。Chromium で「👨‍👩‍👧あ」を数えると、length は9、Intl.Segmenter(granularity: grapheme)は2でした。濁点が分かれる例や絵文字の文字数のずれは、関連記事「文字化けの原因8選|濁点分離・utf8mb4・絵文字の文字数」で扱っています。

Shift_JISとCP932の違い(~・①・髙)

この節では、同じ「Shift_JIS」という名前でも表が違うこと、~・①・髙 が言語やツールによって変換できたりできなかったりする理由が分かります。

CP932(Windows-31J・MS932)は、Shift_JIS に NEC や IBM の文字(①・Ⅰ・髙 など)を足した Windows の版です。さらに、いくつかの記号で Unicode への対応づけが違います。代表が「~」です。

文字 Python shift_jis Python cp932 Java MS932 ブラウザのフォーム送信
あ U+304282 A082 A082 A082 A0
① U+2460なし(エラー)87 4087 4087 40
髙 U+9AD9なし(エラー)EE E0FB FCFB FC
~ U+FF5E(全角チルダ)なし(エラー)81 6081 6081 60
〜 U+301C(波ダッシュ)81 6081 603F(? に置き換え)〜 として送信

表から分かることは3つです。

181 60 の読み方が2通り

Python の shift_jis は 81 60 を 〜 U+301C と読み、cp932 とブラウザは ~ U+FF5E と読んだ。Python の cp932 は 〜 を 81 60 にできるが、読み戻すと ~ に変わる(往復で別の文字になる)。

2Java は黙って ? にする

getBytes("MS932") は表にない 〜 を 3F(?)に置き換え、例外を出さなかった。Shift_JIS を指定すると、今度は ~・①・髙 が 3F になった。

3髙 は2つのバイト列がある

EE E0(NEC が選んだ IBM 拡張)と FB FC(IBM 拡張)のどちらを読んでも 髙 になった。書き出す側の実装で、どちらになるかが違う。

ブラウザの列は、<meta charset="shift_jis"> のページのフォームに文字を入れて送信し、送られた URL を Chromium で記録した結果です。

あ  q=%82%A0
髙  q=%FB%FC
~  q=%81%60
〜  q=%26%2312316%3B
①  q=%87%40
😀  q=%26%23128512%3B
¥  q=%5C

Shift_JIS にない 〜 と 😀 は、&#12316;・&#128512; という文字参照の形で送られました。WHATWG Encoding Standard は、Shift_JIS への符号化で ED・EE の行(ポインター 8272〜8835)を使わないと決めているため、髙 は FB FC になります。上のツールの「文字 → コード」も同じ決まりに合わせており、髙 は FB FC、① は 87 40、~ は 81 60、〜 は「なし」と表示されました。Python の cp932 が書き出す EE E0 も、読めば同じ 髙 になる値です。

名前にも注意が要ります。Oracle の公式ドキュメントでは、Java の Shift_JIS(別名 sjis・shift_jis)と windows-31j(別名 MS932)は別の文字コードです。WHATWG では、shift_jis・sjis・windows-31j・ms932 がすべて同じ1つの Shift_JIS(CP932 に近い表)の別名です。Python では sjis は shift_jis、ms932 と windows-31j は cp932 の別名でした。Windows で作った日本語のファイルを読むときは、名前を「Shift_JIS」ではなく「CP932」(Java は MS932)と指定するのが安全です。

Excel で作った CSV を Java で読む

避ける文字コード名 Shift_JIS で読む。①・髙・~ が ? や別の文字になる
→
代わりに文字コード名 windows-31j(MS932)で読む。Python なら cp932

見分ける問い:「そのファイルは Windows のアプリで作られたか」

iconv でも同じ違いが出ました。SHIFT_JIS を指定すると ~ は変換できず、CP932 なら 81 60 になります。

$ printf ~ | iconv -f UTF-8 -t SHIFT_JIS
iconv: illegal input sequence at position 0
exit=1
$ printf ~ | iconv -f UTF-8 -t CP932 | xxd
00000000: 8160                                     .`

ASCIIコード表(0〜127と制御文字)

この節では、ASCII コードの範囲と、よく使う文字・制御文字の番号が分かります。0〜127 の全部は、上のツールの「ASCII コード表」で一覧にできます。

ASCII は 0〜127 の128個に、英数字・記号と、画面に出ない制御文字を割り当てた表です。UTF-8 の 0〜127 は ASCII と同じなので、英数字だけのファイルは ASCII としても UTF-8 としても読めます。

10進 16進 文字・名前 メモ
00x00NULC 言語の文字列の終わり
90x09HT(タブ)\t
100x0ALF(改行)\n。Linux・macOS の改行
130x0DCR(復帰)\r。Windows の改行は CR LF
270x1BESC端末の色指定・ISO-2022-JP の切り替え
320x20空白(SP)半角スペース
48〜570x30〜0x390〜9数字。'0' は 48
65〜900x41〜0x5AA〜Z大文字
97〜1220x61〜0x7Aa〜z小文字。大文字との差は 32
920x5C\(バックスラッシュ)日本語の Windows では ¥ に見えることがある
1270x7FDEL制御文字

0x5C は、Shift_JIS の元になった JIS X 0201 では「¥」の位置です。Python の shift_jis と cp932 は 0x5C を どちらも \(U+005C)と読みました。一方、ブラウザで Shift_JIS のページから「¥」(U+00A5)を送ると、0x5C(q=%5C)になりました。¥ と \ が入れ替わって見えるのは、この1バイトの位置を共有しているためです。

改行コード(CR LF と LF)の違いが Git で問題になる場合は、関連記事「Git改行コード設定|autocrlfと.gitattributesの違い」で扱っています。ターミナルで改行コードを見るには cat -A が使え、CR LF の行は末尾が ^M$ と表示されました。

BOMと見えない文字の見つけ方

この節では、BOM・ゼロ幅スペース・全角空白・NBSP のような見えない文字が起こす不具合と、その見つけ方が分かります。

BOM(バイトオーダーマーク)は、ファイルの先頭に付ける U+FEFF です。UTF-8 では EF BB BF の3バイト、UTF-16 ではバイトの順番(リトルエンディアンなら FF FE)を示します。Excel は BOM の付いた UTF-8 の CSV を UTF-8 として開くため、CSV では付けることがあります。一方、プログラムの側では、先頭の列名に BOM がくっついて、一致しないことがあります。

$ od -An -tx1 utf8bom.txt
 ef bb bf e3 81 82 e3 81 84 e3 81 86 0a

Python で BOM 付きの文字列を区切ると、列名は '\ufeffid' になり、'id' と一致しませんでした。読み込むときに encoding="utf-8-sig" を指定すると BOM が取り除かれます。JavaScript の trim() は U+FEFF を空白として取り除きましたが、ゼロ幅スペース U+200B は取り除きませんでした。

BOM "id" true ZWSP false

見えない文字は、上のツールの「文字 → コード」に貼ると名前で表示されます。ツールの見本ボタン「見えない文字」で、a と b の間のゼロ幅スペースと末尾の BOM が、それぞれ「(ゼロ幅スペース)」「(BOM(ゼロ幅))」と表示されました。

  • 1BOM(U+FEFF)CSV の先頭の列名が一致しない・JSON の読み込みでエラー。Python は utf-8-sig で読む
  • 2ゼロ幅スペース(U+200B)Web ページやチャットからコピーした名前・URL に混ざる。見た目は同じでも比較で一致しない
  • 3全角空白(U+3000)コードに混ざると構文エラー。ツールでは「(全角空白)」と表示される
  • 4NBSP(U+00A0)HTML の &nbsp; をコピーすると入る。UTF-8 で C2 A0。Shift_JIS には無い
  • 5CR(0x0D)Windows で作ったシェルスクリプトで「bad interpreter」の原因になる

自分で確かめる(ターミナルで1行)

ファイルの中から全角空白・ゼロ幅スペース・NBSP・BOM を探すには、grep の -P が使えます。最初に試したときは、ロケールが UTF-8 でなかったため、次のエラーが出ました。

$ grep -nP '[\x{200B}\x{3000}\x{00A0}\x{FEFF}]' hidden.csv
grep: character code point value in \x{} or \o{} is too large

LC_ALL=C.UTF-8 を付けると、見えない文字を含む行だけが出ました。

$ LC_ALL=C.UTF-8 grep -nP '[\x{200B}\x{3000}\x{00A0}\x{FEFF}]' hidden.csv
2:1,田中 太郎
3:2,佐藤​花子

3行目は見た目では分かりませんが、「佐藤」と「花子」の間にゼロ幅スペースがあります。英数字だけのはずのファイルなら、grep -nP '[^\x00-\x7F]' で ASCII 以外の文字を含む行を探せます。Python では repr() で表示すると 'user_id\u200b\n' のように番号で見えます。

コードに全角空白が混ざって構文エラーになったときも、エラーの行をツールに貼ると、どこに U+3000 があるかが分かります。

文字化けの仕組み(どの組み合わせで何に化けるか)

この節では、保存した文字コードと開いた文字コードの組み合わせごとに、どんな文字化けになるかと、化けた文字から原因を当てる方法が分かります。

文字化けは、バイトそのものは壊れておらず、読む側の文字コードが違うだけのことが多いです。Python で「あいう文字」を保存し、別の文字コードで開いた結果です。

保存した文字コード 開いた文字コード 見え方 特徴
UTF-8CP932(Shift_JIS)縺ゅ>縺�譁�蟄�「縺」「譁」など見慣れない漢字が多い
CP932UTF-8����������� が並ぶ。元に戻せないことが多い
EUC-JPCP932、「、、、ヲハクサ�半角カナと記号が並ぶ
UTF-8UTF-8あいう文字正しく読める

「縺」で始まる文字化けは、UTF-8 の「あ」E3 81 82 の先頭2バイト E3 81 を、Shift_JIS の1文字として読んだものです。上のツールの「コード → 文字」に E3 81 82 を入れると、UTF-8 では「あ」、Shift_JIS では「縺�」と並べて表示されました。化けた文字をツールに貼って番号を見ると、どの組み合わせで読んだかが当てられます。

次の順に確かめると、原因を絞り込めます。

  1. 1ファイルの本当の文字コードを調べるnkf --guess・file・先頭のバイト(EF BB BF なら BOM 付き UTF-8)
  2. 2開く側の指定を確かめるエディタの表示・open(..., encoding=)・HTTP の Content-Type の charset
  3. 3化けた文字の形を見る縺・譁 なら UTF-8 を Shift_JIS で、� の連続なら Shift_JIS を UTF-8 で読んでいる
  4. 4正しい文字コードで開き直す保存し直す前に、元のファイルを残しておく
  5. 5変換して保存するなら、表に無い文字を確かめるUTF-8 から CP932 にすると、絵文字・€ などは変換できない

Excel で CSV が化ける場合の手順は関連記事「CSV文字化けの直し方|エクセルで今すぐ直す手順とUTF-8で直らない原因」で、URL の %E3%81%82 のような形は「URL エンコード・デコード|%E3%81%82 の読み方と変換ツール・言語別の違い」で扱っています。

言語別の文字コード変換(Python・JavaScript・Java・PHP・Go)

この節では、文字と番号・バイトの相互変換を、5つの言語で書く方法と実行結果が分かります。

Python

s = "あ"
print(ord(s), hex(ord(s)))           # 12354 0x3042
print(chr(0x3042), "\u3042", "\U0001F600")
print(s.encode("utf-8").hex(" "))    # e3 81 82
print(s.encode("cp932").hex(" "))    # 82 a0
print(bytes.fromhex("E3 81 82").decode("utf-8"))
print(ascii("あ😀"))                  # '\u3042\U0001f600'

Shift_JIS のバイトを UTF-8 として読むと、次のエラーになりました。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte

このエラーの直し方は関連記事「UnicodeDecodeErrorの原因と直し方|cp932・utf-8・BOM」で詳しく扱っています。逆に、表に無い文字を CP932 にしようとすると次のエラーです。

UnicodeEncodeError: 'cp932' codec can't encode character '\U0001f600' in position 0: illegal multibyte sequence
UnicodeEncodeError: 'shift_jis' codec can't encode character '\uff5e' in position 0: illegal multibyte sequence

JavaScript(ブラウザ・Node.js)

"あ".codePointAt(0).toString(16);          // '3042'
String.fromCodePoint(0x3042, 0x1F600);     // 'あ😀'
new TextEncoder().encode("あ");            // Uint8Array [227, 129, 130]
new TextDecoder("shift_jis").decode(new Uint8Array([0x82, 0xA0])); // 'あ'
new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array([0x82, 0xA0]));

TextEncoder は UTF-8 にしか変換できません。TextDecoder は Shift_JIS・EUC-JP なども読めます。fatal: true を付けた最後の行は、次のエラーになりました(Node.js 22)。付けないと、読めないバイトは � に置き換わります。

TypeError: The encoded data was not valid for encoding utf-8

Java

String s = "あ";
System.out.printf("U+%X%n", s.codePointAt(0));                 // U+3042
byte[] u8 = s.getBytes(StandardCharsets.UTF_8);               // E3 81 82
byte[] sj = s.getBytes("MS932");                              // 82 A0
String back = new String(sj, "MS932");                        // あ
String emoji = new String(Character.toChars(0x1F600));        // 😀

Java の getBytes と new String は、変換できない文字を ?(3F)や � に置き換え、例外を出しませんでした。誤りを例外で知りたいときは CharsetEncoder を使い、onUnmappableCharacter(CodingErrorAction.REPORT) を指定します。

PHP

$s = "あ😀";
echo strlen($s), " ", mb_strlen($s), "\n";                 // 7 2
echo sprintf("U+%04X", mb_ord("あ")), "\n";                // U+3042
echo bin2hex(mb_convert_encoding("あ", "SJIS-win", "UTF-8")), "\n"; // 82a0
echo json_encode("あ"), " ", json_encode("あ", JSON_UNESCAPED_UNICODE), "\n"; // "\u3042" "あ"

PHP の json_encode は、何も指定しないと日本語を \u3042 の形にしました。Windows の CSV 向けには、mbstring の SJIS-win(CP932 相当)を指定します。

Go

s := "あ😀"
fmt.Println(len(s), utf8.RuneCountInString(s)) // 7 2
for i, r := range s {
    fmt.Printf("%d U+%04X %q %d\n", i, r, r, utf8.RuneLen(r))
}
fmt.Printf("% X\n", []byte(s))
7 2
0 U+3042 'あ' 3
3 U+1F600 '😀' 4
E3 81 82 F0 9F 98 80

Go の文字列は UTF-8 のバイト列で、range で回すと1文字(rune)ずつ取り出せます。Shift_JIS のバイト(82 A0)を utf8.ValidString で調べると false でした。Shift_JIS との変換は標準ライブラリには無く、golang.org/x/text/encoding/japanese を使います。

コマンドで文字コードを調べる・変換する(file・nkf・iconv・xxd)

この節では、ファイルの文字コードを判定するコマンドと、変換・16進表示のコマンドの実行結果が分かります。

「あいう」を UTF-8・BOM 付き UTF-8・CP932・EUC-JP・UTF-16 で保存したファイルを用意し、file と nkf --guess で判定しました。

保存した文字コード file file -i nkf --guess
ASCII(abc)ASCII textus-asciiASCII (LF)
UTF-8Unicode text, UTF-8 textutf-8UTF-8 (LF)
UTF-8(BOM 付き)UTF-8 (with BOM) textutf-8UTF-8 (BOM) (LF)
UTF-8(CR LF)with CRLF line terminatorsutf-8UTF-8 (CRLF)
CP932Non-ISO extended-ASCII textunknown-8bitShift_JIS (LF)
EUC-JPISO-8859 textiso-8859-1EUC-JP (LF)
UTF-16(BOM 付き)UTF-16, little-endian textutf-16leUTF-16 LE (BOM) (LF)

file は短い日本語のファイルの Shift_JIS・EUC-JP を判定できず、ISO-8859 などと答えました。nkf は日本語の文字コードを当てましたが、どちらも中身から推測しているだけなので、短いファイルや英数字が大半のファイルでは外れることがあります。確実なのは、作った側に文字コードを確かめることです。

16進で中身を見る(xxd・od)

$ xxd utf8.txt
00000000: e381 82e3 8184 e381 860a                 ..........
$ xxd sjis.txt
00000000: 82a0 82a2 82a4 0a                        .......
$ printf あ | xxd -p
e38182

xxd が無い環境では、od -An -tx1 ファイル名 で同じように1バイトずつ見られます(od は coreutils に入っています)。

変換する(iconv・nkf)

iconv -f CP932 -t UTF-8 sjis.txt > utf8.txt   # Shift_JIS(CP932)→ UTF-8
iconv -f UTF-8 -t CP932 utf8.txt > sjis.txt   # UTF-8 → CP932
nkf -w sjis.txt > utf8.txt                     # 判定して UTF-8 に
nkf -s utf8.txt > sjis.txt                     # Shift_JIS に

iconv は、変換できない文字があると途中で止まり、終了コード1を返しました(止まる前の「A」だけは出力されています)。//TRANSLIT を付けると ? に置き換え、-c を付けると黙って捨てました。

$ printf "A😀B" | iconv -f UTF-8 -t CP932
Aiconv: illegal input sequence at position 1
exit=1
$ printf "A😀B" | iconv -f UTF-8 -t CP932//TRANSLIT
A?B exit=0
$ printf "A😀B" | iconv -c -f UTF-8 -t CP932
AB exit=0
$ iconv -f UTF-8 -t UTF-8 sjis.txt
iconv: illegal input sequence at position 0
exit=1

最後の行のように、-f UTF-8 -t UTF-8 で変換すると、ファイルが正しい UTF-8 かどうかの確認になります。終了コードが0なら UTF-8 として読めるファイルです。

1

判定する

nkf --guess・file -i。推測なので外れることがある。

短いファイルは要注意

2

中身を見る

xxd・od -An -tx1。先頭の EF BB BF で BOM が分かる。

いちばん確実

3

変換する

iconv -f CP932 -t UTF-8。Shift_JIS ではなく CP932 を指定する。

終了コードを見る

4

UTF-8 か確かめる

iconv -f UTF-8 -t UTF-8 ファイル > /dev/null の終了コードが0か。

CI にも入れられる

文字コードのよくあるエラーと直し方

この節では、文字コードが原因で出るエラーの原文と、原因・直し方が分かります。原文はすべて手元で出したものです。

エラー・症状(原文) 原因 直し方
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byteShift_JIS(CP932)のファイルを UTF-8 で読んだopen(..., encoding="cp932")
UnicodeEncodeError: 'cp932' codec can't encode character '\U0001f600'CP932 に無い文字(絵文字など)を書き出したUTF-8 で書き出す。または errors="replace"
'shift_jis' codec can't encode character '\uff5e'Shift_JIS(JIS の表)に ~ が無い文字コード名を cp932 にする
iconv: illegal input sequence at position 0入力の文字コードの指定違い、または変換先に無い文字-f を確かめる。SHIFT_JIS を CP932 に
TypeError: The encoded data was not valid for encoding utf-8TextDecoder(fatal)に UTF-8 でないバイトを渡したnew TextDecoder("shift_jis") で読む
grep: character code point value in \x{} or \o{} is too largeロケールが UTF-8 でないLC_ALL=C.UTF-8 grep -P ...
Java で ~ や 〜 が ? になる(例外は出ない)Shift_JIS と MS932 の表の違いWindows のファイルは MS932(windows-31j)
列名 id が一致しない('\ufeffid')BOM 付き UTF-8 の CSVPython は utf-8-sig で読む
絵文字の後半が欠ける("\ud83d")UTF-16 の単位で切り詰めた[...s] や Intl.Segmenter で切る

Windows のコンソールに print したときの UnicodeEncodeError: 'cp932' は、ファイルではなく出力先(コンソール)の文字コードの問題です。環境変数 PYTHONUTF8=1 などで出力を UTF-8 にすると直ります。

どの文字コードを選ぶか(判断表)

この節では、新しくファイルやシステムを作るとき、受け取ったファイルを読むときに、どの文字コードを指定するかが分かります。

新しく作るものは UTF-8(BOM なし)が基本です。受け取るものは、作った側の文字コードに合わせます。

場面 選ぶ文字コード 理由・注意
Web ページ・API・JSONUTF-8HTML は <meta charset="utf-8">。JSON は UTF-8 が標準
ソースコード・設定ファイルUTF-8(BOM なし)BOM があるとシェルスクリプトの先頭行が読めないことがある
Excel でそのまま開く CSVBOM 付き UTF-8、または CP932相手の Excel・システムに合わせる。絵文字があるなら UTF-8
Windows で作られた日本語ファイルを読むCP932(Java は MS932)Shift_JIS を指定すると ①・髙・~ が化ける
データベース(MySQL)utf8mb4utf8(utf8mb3)は4バイトの絵文字を保存できない
以前の Unix のファイル・メールEUC-JP・ISO-2022-JPnkf --guess で確かめてから UTF-8 に変換
文字数を数える・切るコードポイントか書記素で数えるJavaScript・Java の length は UTF-16 の単位

HTML の文字コードの宣言は、W3C の解説「Declaring character encodings in HTML」に従い、ファイルの先頭1024バイト以内に置きます。

よくある質問

この節では、文字コードについてよく検索される疑問への短い答えが分かります。

Q. 文字コードと文字セット(charset)は同じですか? A. ふだんは同じ意味で使われます。厳密には、文字セット(文字集合)は番号の表、文字コードは表と符号化方式の組み合わせです。HTML や HTTP の charset=utf-8 は、符号化方式の名前を書く欄です。

Q. Unicode と UTF-8 の違いは何ですか? A. Unicode は文字に番号を付けた表、UTF-8 はその番号をバイトにする方式の1つです。「あ」は Unicode で U+3042、UTF-8 で E3 81 82 です。

Q. 「あ」の文字コードは? A. Unicode は U+3042(10進 12354)、UTF-8 は E3 81 82、UTF-16 は 30 42、Shift_JIS は 82 A0、EUC-JP は A4 A2 です。

Q. \u3042 を日本語に戻すには? A. 上のツールの「コード → 文字」に貼ります。Python なら "\\u3042".encode().decode("unicode_escape")、JavaScript なら JSON.parse('"\\u3042"') で戻せます。

Q. ASCII コードの A は何番ですか? A. 65(16進 0x41)です。a は 97(0x61)で、大文字と小文字の差は 32 です。0 は 48(0x30)です。

Q. Shift_JIS と CP932 はどちらを指定すればよいですか? A. Windows で作られた日本語のファイルなら CP932(Java は MS932・windows-31j)です。Shift_JIS を指定すると、①・髙・~ などが変換できないか、別の文字になります。

Q. 絵文字は Shift_JIS で保存できますか? A. できません。手元の Python・iconv では変換がエラーになり、Java は ? に置き換えました。ブラウザのフォーム送信では &#128512; の形で送られました。絵文字を扱うなら UTF-8 にします。

Q. ファイルの文字コードを確実に知る方法はありますか? A. ファイルの中だけから確実に決める方法はありません。BOM があれば決まりますが、無いときは nkf や file の推測になります。作った側に確かめるのが確実です。

Q. UTF-8 の BOM は付けるべきですか? A. ソースコード・Web・JSON では付けないのが一般的です。Excel で開く CSV では、付けると Excel が UTF-8 として開きます。受け取る側の決まりに合わせます。

Q. ツールに入れた文字はどこかに送られますか? A. 送られません。変換はすべてブラウザの中で行います。

まとめ

  • 文字コードは「文字集合(番号の表)」と「符号化方式(バイトにする方法)」の組み合わせ。Unicode は表、UTF-8 は方式。「あ」は U+3042、UTF-8 で E3 81 82、Shift_JIS で 82 A0。
  • UTF-8 は1〜4バイトで、先頭のバイトで長さが分かる。ひらがな・漢字の多くは3バイト、絵文字は4バイト。
  • JavaScript と Java の length は UTF-16 の単位を数えるので、絵文字1つが2になる。Python はコードポイント、Go はバイトを数える。
  • Shift_JIS と CP932 は表が違い、~・①・髙 で結果が分かれた。Windows のファイルは CP932(Java は MS932)を指定する。Java は変換できない文字を例外なしで ? にした。
  • 見えない文字(BOM・ゼロ幅スペース・全角空白・NBSP)は、上のツールで名前を表示するか、LC_ALL=C.UTF-8 grep -P で探す。

参考・出典

確認日はいずれも 2026年11月9日です。

  • The Unicode Consortium「The Unicode Standard」:https://www.unicode.org/standard/standard.html
  • IETF「RFC 3629 UTF-8, a transformation format of ISO 10646」:https://www.rfc-editor.org/rfc/rfc3629
  • IETF「RFC 2781 UTF-16, an encoding of ISO 10646」:https://www.rfc-editor.org/rfc/rfc2781
  • WHATWG「Encoding Standard」(Shift_JIS・index Shift_JIS pointer):https://encoding.spec.whatwg.org/
  • Oracle「Supported Encodings」(Java SE 21):https://docs.oracle.com/en/java/javase/21/intl/supported-encodings.html
  • Microsoft Learn「Code Page Identifiers」:https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
  • Python「codecs --- codec レジストリと基底クラス」:https://docs.python.org/ja/3/library/codecs.html
  • MDN「String.prototype.codePointAt()」:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt
  • MDN「TextDecoder」:https://developer.mozilla.org/ja/docs/Web/API/TextDecoder
  • PHP マニュアル「mb_convert_encoding」:https://www.php.net/manual/ja/function.mb-convert-encoding.php
  • Go「Package utf8」:https://pkg.go.dev/unicode/utf8
  • W3C「Declaring character encodings in HTML」:https://www.w3.org/International/questions/qa-html-encoding-declarations

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「文字コード表・変換ツール|Unicode・UTF-8・Shift_JISの調べ方」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

成長のヒミツ、 ぜんぶ丸わかり