UTF-8で環境依存文字?


PHPで機種依存文字の置き換え」で自分の無知ぶりを発揮してしまったわけですが
Chromeで顔文字が表示されないという事実を知ってしまい、ちょっとあせっている今日この頃...

MySQLで文字コードをutf8mb4で指定しているし、𩸽もちゃんと表示できるからUTF-8の4バイト対応はOKなんて思っていたのでオロオロ しています。

とりあえず、「数値エンティティ」に直せばいけるかもと思い検証したのが、下記のコード

// 元の文字列
$str = 'a1あア𐌰𐐀𐒀𐰧𑃐𝐀🀄🃏🆗🈲🌂😁🚀𠀠真𩸽';
// 変換なしで出力
// a1あア𐌰𐐀𐒀𐰧𑃐𝐀🀄🃏🆗🈲🌂😁🚀𠀠真
echo $str, PHP_EOL, '<br>', PHP_EOL;
// convmapをU+10000~U+10FFFFに指定
$convmap = array(0x10000, 0x10FFFF, 0, 0xFFFFFF);
// U+10000より後の文字を数値エンティティに変換した文字列で出力
// a1あア&#66352;&#66560;&#66688;&#68647;&#69840;&#119808;&#126980;&#127183;&#127383;&#127538;&#127746;&#128513;&#128640;&#131104;&#194887;
echo mb_encode_numericentity($str, $convmap, 'UTF-8'), PHP_EOL;

IE11、FireFox、Chromeの出力結果がこちら

IE11で表示

FireFoxで表示

Chromeで表示

やっぱり「数値エンティティ」にしてもやっぱりだめか...ってあれ?IE11で「CJK互換漢字補助」の文字が表示されていない

はい、泣きそうです

どうしよー ん?待てよ。直接文字だけ出力しているから表示できないフォントになっているだけじゃね?

ということで、htmlで出力します(ついでにChromeも確認)。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style type="text/css">
            body {
                font-family: メイリオ, Meiryo;
            }
        </style>
    </head>
    <body>
        <p>a1あア𐌰𐐀𐒀𐰧𑃐𝐀🀄🃏🆗🈲🌂😁🚀𠀠真𩸽</p>
        <p>a1あア&#66352;&#66560;&#66688;&#68647;&#69840;&#119808;&#126980;&#127183;&#127383;&#127538;&#127746;&#128513;&#128640;&#131104;&#194887;&#171581;</p>
    </body>
</html>

結果

IE11で表示

Chromeで表示

よかったIE11での表示は直ってる
だけどやっぱりChromeは元のまま...

ここまでで分かったのは「U+10000~U+1FFFF」までの文字がうまく表示できていないということです。

よく分からない文字は良いにしても絵文字はスマートフォンから入力される可能性が高いので何とかしなければなりません。絵文字をどうするか...

Emoji」を見ると「Chrome」と「Android4.3以下」以外は対応するフォントを指定すれば絵文字の表示は大丈夫そうですが、そのまま「Chrome」や「Android4.3以下」は無視というわけにもいきません。

そういえば去年「Twitterで絵文字がどうの」って記事をどこかで見たような気がしたので探しました。

Twitter、872個の絵文字をオープンソース化
Twitter Emoji (Twemoji)
Twitter 絵文字一覧

早速試してみます。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style type="text/css">
            body {
                font-family: メイリオ, Meiryo;
            }
        </style>
        <script src="//twemoji.maxcdn.com/twemoji.min.js"></script>
    </head>
    <body>
        <p id="test"></p>
        <script type="text/javascript">
            var div = document.createElement('div');
            div.textContent = 'a1あア𐌰𐐀𐒀𐰧𑃐𝐀🀄🃏🆗🈲🌂😁🚀𠀠真𩸽';
            document.body.appendChild(div);
            twemoji.parse(document.body);
        </script>
    </body>
</html>

Chromeでの表示

絵文字以外はだめですが、絵文字はきちんと変換されています。

画像はGitHubのものの方が好みですが、GitHubの画像に変換してくれるものは見つかりませんでした。

Twitter Emoji (Twemoji)の詳しい使い方はこれから覚えていきますが、なんとかなりそうなのでホッとしています

追記
emojify.js」のissueにunicodeからの変換があがっていて、将来のアップデートでカバーするとのことなので、こちらにも期待したいです。