JSONにおけるUnicode

JSONがUnicode文字をどのように扱うかを理解しましょう。エンコーディング要件、エスケープシーケンス、絵文字・CJK文字・サロゲートペアに関するよくある落とし穴を解説します。

Syntax

詳細な説明

JSONはUnicodeベースの形式として定義されています。仕様(RFC 8259)はJSONテキストがUTF-8でエンコードされなければならないと規定しており、すべてのJSONパーサーは最低限UTF-8を受け入れることが求められています。JSON文字列は任意のUnicode文字を、直接(リテラルのUTF-8バイトとして)または \uXXXX エスケープ構文で含めることができます。

エンコーディング要件:

RFC 8259は、システム間で交換されるJSONは「UTF-8を使用してエンコードされなければならない(MUST)」と規定しています。以前の仕様ではUTF-16とUTF-32も許可されていましたが、現在の標準はUTF-8を強く推奨しています。実際には、Web上のほぼすべてのJSONがUTF-8エンコードです。JSONファイルが別のエンコーディング(Latin-1やShift-JISなど)で保存されている場合、パーサーは非ASCII文字に対して不正な結果を生成するかエラーをスローする可能性があります。

Unicodeエスケープシーケンス:

\uXXXX エスケープを使用して任意のUnicode文字を表現できます。XXXX は4桁の16進コードポイントです。例:

  • \u0041 = A
  • \u00E9 = アキュートアクセント付きe
  • \u4E16 = 「世」(中国語の文字)
  • \u2603 = 雪だるま

リテラル文字とそのエスケープシーケンスは意味的に同一です: "caf\u00E9""cafe\u0301" は似て見えるかもしれませんが、異なるUnicodeシーケンス(合成済み vs 結合文字)を表します。

絵文字とサロゲートペア:

基本多言語面(BMP)外の文字(ほとんどの絵文字を含む)はU+FFFFを超えるコードポイントを持ち、単一の \uXXXX エスケープでは表現できません。代わりにUTF-16サロゲートペア(連続する2つの \u エスケープ)が必要です:

{"emoji": "\uD83D\uDE00"}

これはU+1F600(にっこり笑顔)を表します。モダンなJSONパーサーはサロゲートペアを自動的に処理しますが、一部の古いまたは単純なパーサーでは文字化けやエラーが発生する可能性があります。手書きでJSONを記述する場合は、リテラルの絵文字文字を含める方がシンプルで明確です。

制御文字:

JSON文字列にはリテラルの制御文字(U+0000からU+001F)を含めてはいけません。これらはエスケープする必要があります: 改行は \n、タブは \t、キャリッジリターンは \r、その他の制御文字は \uXXXX を使用します。JSON文字列にリテラルのnullバイト(U+0000)を含めようとすると無効であり、パースエラーが発生します。

開発者がよくやるミス:

最も一般的なミスは、特にWindowsでテキストエディタがWindows-1252をデフォルトにする場合に、間違ったエンコーディングでJSONファイルを保存することです。もうひとつのミスは、必要のない文字に対してエスケープシーケンスを生成することです。\u エスケープは常に有効ですが、利点なく可読性を低下させます。一部の開発者はサロゲートペアを文字列境界をまたいで分割したり、2つの半分を個別に処理して無効なUnicodeを生成してしまうこともあります。もうひとつの問題は、比較前にUnicode文字列を正規化しないことです: "cafe\u0301"(e + 結合アクセント)と "caf\u00E9"(合成済み)はレンダリング時には同じに見えますが、異なるバイトシーケンスです。

ベストプラクティス:

JSONファイルは常にBOMなしのUTF-8で保存してください。可読性のためにエスケープシーケンスではなくリテラルのUnicode文字を使用してください。\uXXXX エスケープは制御文字または伝送チャネルがUTF-8をサポートしていない場合にのみ使用してください。文字列比較時にはUnicode正規化に注意してください。CJK文字、絵文字、アラビア語やヘブライ語などの右から左に書くスクリプトを含む非ASCII入力でアプリケーションをテストしてください。

ユースケース

中国語の商品名、アラビア語の説明、絵文字の評価を含む多言語商品カタログをJSONで正しくエンコードし、エンコーディングエラーを回避する。

試してみる — JSON Formatter

フルツールを開く