Shift-JISで、PHP+MYSQLのサイトを構築すると「特殊文字の壁」があります。
どういうことかというと、UTF-8のほうが表現できる文字数(特殊漢字など)が多く、Shift-JISでは表現できない文字(特殊文字)があるという点です。
これがShift-JIS文字化けの要因の一つです。
ただ近年「SJIS-win」「CP932」などを使用すると、Shift-JISでも特殊文字が使用できるようになりました。
これによりHTMLでShift-JISを使う分にはさほど困ることは起こらなくなりました。
ただ、Shift-JISでは特殊文字は「&#文字」で表現されます。
例えば「塡」という漢字は「塡」に変換されて保存されます。
見た目は数字ですが、ブラウザを通すと「塡」という文字で表示されます。
そのためHTMLで使用する分には、&#文字のままでOKなのです。
ただしこのままだと、CSV出力など、テキストファイルに出力する時に、&#文字のまま出力されてしまいます。
出力したCSVファイルに&#文字がそのまま入っていたら、それこそ文字化け扱いです。
今回、これを何とかすべく、Shift-JISのまま&#文字を本来の文字へ逆変換する方法について調べてみました。
&#文字の一般的な逆変換方法
&#文字を通常の文字に戻すためには、「html_entity_decode()」関数を使用します。
&#文字を通常文字に変換してくれます。
使い方は以下の通りです。
$outcode = html_entity_decode("塡");
これだけで「塡」という文字に変換してくれます。
簡単簡単。
とこの時は思いましたが、落とし穴がありました。
html_entity_decode関数を使用しても変換されないケースがありました。
html_entity_decode()関数を使用すれば、&#文字が本来の文字に変換されるのですが、変換されず&#文字のまま出力されているケースがありました。
なぜ?
と思い調べてみたところ、次のことがわかりました。
「&#」が「&#」で保存されていました。
「&」もHTML上では特殊文字の一つです。
文字化けさせないように特殊文字「&」として保存します。
そのため、「塡」は「塡」と保存されていました。
「&#22625」をhtml_entity_decode()関数で変換すると、「塡」になります。
&→&に変換するだけで、肝心の&#文字は変換してくれません。
なぜならば、&と#の間に「amp;」という文字があるため、特殊文字として認識されないからです。
こういった場合はどうすれば本来の文字に戻せるのでしょうか?
&#文字を本来の文字に戻す方法
「&」が特殊文字で変換されている場合は、次のような方法で対処することができます。
$outcode = html_entity_decode(html_entity_decode("塡"));
html_entity_decode()関数を2回コールします。
1回目のコールで「塡」が「塡」に変換されます。
2回目のコールで「塡」が「塡」に変換されます。
コロンブスの卵的な発想ですが、&を先に「&」に変換してから、本来の文字に変換する方法です。
無論&が変換されていない「塡」を二重にコールしても特に文字化け等は起こりません。
私はこの方法で&#文字を全て本来の文字に逆変換してCSV出力することができました。
今回は思ったより悩みました。
今回は、html_entity_decode()関数で元の文字に戻らない場合があり、その原因がわからずとても悩みました。
文字コードテーブルを作成し強引に変換してみたりなど、いろいろ試行錯誤しましたが、完全に変換されずどこかしら「抜け」がありました。
そんななか、たまたまコーディングミスでhtml_entity_decode()を2回記述してしまいました。ところが変換が上手くでき、要因を調べたところ先述の&が変換の邪魔をしていたことがわかりました。
偶然とはいえ、重要なhtml_entity_decode()関数の癖を知ることができました。
html_entity_decode()関数で意図する変換がされない場合、2回コールするとうまくいくケースがあるかもしれません。