SheepDev

エンコード・文字コード

\u65e5や&を読める文字に戻したい

使うツール

読めるはずの文章が、バックスラッシュや&で始まる記号列になっている。これは、元の文字が壊れたのではなく、ある形式の中へ文字を安全に書くための別表記かもしれません。ただし、すべての記号列を同じデコードへ入れてよいわけではありません。Unicodeエスケープ、HTML文字参照、URLの%表記は、それぞれ別の規則です。

ここでは一文字のあ、絵文字、短いHTML風の文章を使って、どこまで戻るかを試します。出力は文字列として確認し、HTMLやJavaScriptとして実行しません。復元した結果がコードのように見えても、実行する必要はありません。元データがどの形式から来たかを確認しながら進めます。

\u3042を一文字へ戻す

Unicodeエスケープの入力
\u3042

Unicodeエスケープツールのデコードであになります。逆にあをエンコードすると、選んだ表記に応じて\u3042や\u{3042}になります。どちらも文字を参照する記法ですが、受け取る形式が両方を受け付けるとは限りません。JSONの文字列へ入れる用途と、JavaScriptのコードポイント表記を使う用途を分けて選びます。

ログに\u3042と表示されているだけなら、表示用のシリアライズでエスケープされている可能性があります。元の値が本当に六文字の\u3042なのか、あという一文字をログが別表記で見せているのかは、ログの出力方法を確認します。見た目の記号だけを根拠に、保存データが壊れたと決め付けないでください。

絵文字一つに、二組の\uが必要な場合

😀の二つの表記
\u{1F600}
\uD83D\uDE00

一行目はコードポイントを一つで示し、二行目はUTF-16の二単位を使うサロゲートペアです。別々にデコードすると、どちらも😀へ戻ります。二組あるから絵文字が二つ、という意味ではありません。文字数・バイト数の記事で扱う『表示上の文字』と『UTF-16単位』の違いが、エスケープ表記にも現れています。

ペアの片側だけを残した\uD83Dは、不完全な文字としてエラーになります。見た目を短くする目的で片側を削ったり、上限文字数に合わせて途中で切ったりしないでください。形式上の単位を途中で壊す処理は、後から復元できない問題を作ります。文字列を切る必要がある場合は、どの単位で切るかを実装側で決めます。

&は、&を表すための文字参照

HTMLエンティティ変換へ入力
Tom & Jerry
<b>hello</b>

HTMLエンティティのデコードでは、Tom & Jerryと<b>hello</b>という文字列になります。この画面は復元したタグを実行して太字にするための場所ではありません。文字としてのタグを確認することと、HTMLとしてDOMへ挿入することは別です。復元できたから安全にページへ挿入できる、と判断しないでください。

現在の名前付き参照の復元はamp、lt、gt、quot、apos、nbspに対応し、数値参照も扱います。HTMLで定義されるすべての名前を網羅するものではなく、未対応の名前はそのまま残ります。出力に参照らしい文字列が残っても、すぐに壊れたデータと判断せず、対応範囲を確認してください。

&amp;lt;を一回戻しても、<にはならない

層を一つずつ戻した結果
&amp;lt; → &lt; → <

最初のデコードで&amp;が&へ戻り、残りのlt;と合わせて&lt;になります。もう一度デコードすれば<になりますが、二回戻すことが正しいとは限りません。元々『&lt;という書き方』を説明する文章だった可能性もあります。エスケープがなくなるまで繰り返すのではなく、どの形式を何回通ったかを確認します。

JSONの中にHTMLを含む場合など、異なる形式が重なることもあります。その場合も、外側のJSONを正しく解析して中の文字列を取り出す処理と、HTML文字参照を復元する処理を分けます。すべてを置換で一気に直すと、必要な引用符や区切りまで変えてしまう可能性があります。小さな例で、各段階の期待値を決めてください。

%E3%81%82と&#12354;も、同じデコーダーではない

あを表す別々の方式
Unicode: \u3042
HTML: &#12354; / &#x3042;
URL UTF-8: %E3%81%82

HTMLの数値参照はコードポイントを十進数または16進数で示し、URLの%表記はUTF-8のバイトを表します。数字の並びが違うのは、異なる文字を表しているからとは限りません。元の形式が分かれば適切なツールを選べますが、見た目だけで形式が不明な場合は、生成元の仕様を先に確認します。

Unicodeエスケープの現在のデコード対象は\uXXXX、\u{X}、\xXXです。一般的な文字列リテラルの\nや\tを含め、あらゆるエスケープを解析する機能ではありません。JSON全体をこの欄へ入れて復元しようとするのではなく、JSONとしての構文確認にはJSON整形・検証を使います。対応外を無理に置き換えて成功扱いにしないことが、元の意味を守ります。

復元した後も、出力先の規則は残る

デコードで元の文字が分かったら、調査の目的は一段進んでいます。しかし、その文字列をHTML本文、属性、JavaScript、URLへ入れる際は、それぞれに適した扱いが別途必要です。エスケープは一度すればどこでも安全になる処理ではありません。出力先を変えるたびに、その場所で文字がどう解釈されるかを確認します。

報告には、元の記号列、使ったデコード方式、変換回数、得られた文字列を添えます。『文字化けを直した』だけでなく、『HTML参照を一層戻すと意図した&になった』と書けば、生成側と表示側のどちらで変換が重なったかを調べやすくなります。繰り返し変換して見た目を合わせるより、余分な一層が生まれる場所を直すことが再発防止になります。

見えているバックスラッシュは、文字なのか表示方法なのか

ログに\u3042と見えていても、元の値が『あ』で、ログ表示だけがエスケープしている場合があります。逆に、利用者がバックスラッシュとuと数字をそのまま入力した文字列の場合もあります。見た目が同じでも、どの層の文字列をコピーしたかによって復元が必要かどうかは変わります。JSON全体を読んでいるなら、先にJSONの構文として何が値かを確かめます。表示を戻すために文字列置換を重ねる前に、すでにJSONパーサーがエスケープを解釈していないかを確認します。

HTMLの文字参照も同様です。説明文の中で『&lt;と書く』という例を見せたいなら、表示前の文字列に&amp;lt;が必要になる場合があります。それを二回復元して<にすると、説明したかった文字列とは別になります。復元回数は『読めるまで何度でも』ではなく、元の処理で何段階の表現へ変えたかに対応させます。このツールは入力から処理履歴を推測しないので、出力が読めたという理由だけで正しい段階に戻ったと判断しないでください。

参考資料

使うツール

使い方・解説 →