Unicode文字を含むビデオゲーム名を格納するデータベースがありますが、HTML応答に出力するときにこれらのUnicode文字を適切にエスケープする方法がわかりません。
たとえば、Unchartedのような名前ですべてのゲームを印刷すると、次のようになります。
Uncharted: Drake's Fortuneâ„¢
Uncharted 2: Among Thievesâ„¢
Uncharted 3: Drake's Deceptionâ„¢
しかし、これを表示する必要があります:
Uncharted: Drake's Fortune™
Uncharted 2: Among Thieves™
Uncharted 3: Drake's Deception™
クイックJavaScriptエスケープ関数を実行して、™
がどのUnicode文字であるかを確認し、それが\u2122
であることがわかりました。
™
文字を正しく表示できれば、文字列内のすべての文字を完全にエスケープすることに問題はありません。私の推測では、文字列内の各文字の16進表現を何らかの方法で見つけて、PHP Unicode文字を次のようにレンダリングします。
print "™";
HTMLに対応するために文字列をエスケープするUnicodeの最良のアプローチを教えてください。私はしばらく前にJavaScriptに対して同様のことをしましたが、JavaScriptにはエスケープとアンエスケープのための組み込み関数があります。
PHP同様の機能の関数を認識していません。 ord 関数について読みましたが、ASCII特定の文字の文字コード、したがって™
または™
の不適切な表示。この関数は、有効なUnicode文字を含む任意の文字列に適用できるように十分に汎用性があります。
内部にUTF-8でエンコードされた文字列があるようです。PHPは正しく出力しますが、ブラウザはエンコードの自動検出に失敗します(ISO 8859-1またはその他のエンコードを決定します)。
最善の方法は、対応するHTTPヘッダーを送信してTF-8が使用されていることをブラウザーに通知するにすることです。
header("content-type: text/html; charset=UTF-8");
次に、残りのコードをそのままにしておくことができ、エンティティをhtmlエンコードしたり、他の混乱を作成したりする必要はありません。
必要に応じて、さらに<meta>
タグを使用して、生成されたHTMLでエンコーディングを宣言できます。
<meta http-equiv=Content-Type content="text/html; charset=UTF-8">
for HTML <= 4.01<meta charset="UTF-8">
for HTML5HTTPヘッダーは<meta>
タグよりも優先されますが、HTMLをHDに保存してからローカルで読み取る場合は、後者が役立つ場合があります。
Unicodeコードと同等の文字を出力するためのより良い方法を見つけるために多くの時間を費やしましたが、見つけたメソッドが機能しないか、非常に複雑でした。
つまり、JSONは構文「\ u [unicode_code]」を使用してUnicode文字を表すことができます。
echo json_decode('"\u00e1"');
この場合、同等のユニコード文字を出力します。
P.D.単純引用符と二重引用符に注意してください。両方を入れないとうまくいきません。
これを試して:
echo htmlentities("Uncharted: Drakes Fortune™ \n", ENT_QUOTES, "UTF-8");
// PHP 7.0
var_dump(
IntlChar::chr(0x2122),
IntlChar::chr(0x1F638)
);
var_dump(
utf8_chr(0x2122),
utf8_chr(0x1F638)
);
function utf8_chr($cp) {
if (!is_int($cp)) {
exit("$cp is not integer\n");
}
// UTF-8 prohibits characters between U+D800 and U+DFFF
// https://tools.ietf.org/html/rfc3629#section-3
//
// Q: Are there any 16-bit values that are invalid?
// http://unicode.org/faq/utf_bom.html#utf16-7
if ($cp < 0 || (0xD7FF < $cp && $cp < 0xE000) || 0x10FFFF < $cp) {
exit("$cp is out of range\n");
}
if ($cp < 0x10000) {
return json_decode('"\u'.bin2hex(pack('n', $cp)).'"');
}
// Q: Isn’t there a simpler way to do this?
// http://unicode.org/faq/utf_bom.html#utf16-4
$lead = 0xD800 - (0x10000 >> 10) + ($cp >> 10);
$trail = 0xDC00 + ($cp & 0x3FF);
return json_decode('"\u'.bin2hex(pack('n', $lead)).'\u'.bin2hex(pack('n', $trail)).'"');
}