[PHP]Shift-JISの&#文字列をUTF-8文字に逆変換する

2021年6月17日

 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()」関数を使用します。

&#文字を通常文字に変換してくれます。
使い方は以下の通りです。

これだけで「塡」という文字に変換してくれます。
簡単簡単。
とこの時は思いましたが、落とし穴がありました。

html_entity_decode関数を使用しても変換されないケースがありました。

html_entity_decode()関数を使用すれば、&#文字が本来の文字に変換されるのですが、変換されず&#文字のまま出力されているケースがありました。

なぜ?

と思い調べてみたところ、次のことがわかりました。

「&#」が「&#」で保存されていました。

「&」もHTML上では特殊文字の一つです。
文字化けさせないように特殊文字「&」として保存します。
そのため、「塡」は「塡」と保存されていました。

「&#22625」をhtml_entity_decode()関数で変換すると、「塡」になります。

&→&に変換するだけで、肝心の&#文字は変換してくれません。
なぜならば、&と#の間に「amp;」という文字があるため、特殊文字として認識されないからです。

こういった場合はどうすれば本来の文字に戻せるのでしょうか?

&#文字を本来の文字に戻す方法

「&」が特殊文字で変換されている場合は、次のような方法で対処することができます。

html_entity_decode()関数を2回コールします。
1回目のコールで「塡」が「塡」に変換されます。
2回目のコールで「塡」が「塡」に変換されます。

コロンブスの卵的な発想ですが、&を先に「&」に変換してから、本来の文字に変換する方法です。

無論&が変換されていない「塡」を二重にコールしても特に文字化け等は起こりません。

私はこの方法で&#文字を全て本来の文字に逆変換してCSV出力することができました。

今回は思ったより悩みました。

今回は、html_entity_decode()関数で元の文字に戻らない場合があり、その原因がわからずとても悩みました。

文字コードテーブルを作成し強引に変換してみたりなど、いろいろ試行錯誤しましたが、完全に変換されずどこかしら「抜け」がありました。

そんななか、たまたまコーディングミスでhtml_entity_decode()を2回記述してしまいました。ところが変換が上手くでき、要因を調べたところ先述の&が変換の邪魔をしていたことがわかりました。

偶然とはいえ、重要なhtml_entity_decode()関数の癖を知ることができました。

html_entity_decode()関数で意図する変換がされない場合、2回コールするとうまくいくケースがあるかもしれません。

今回のレポートは以上です。
読んでいただいてありがとうございました。


ホームページに関するお悩み事やご相談事がございましたら私どもまでご連絡ください。 鋭意ご対応申し上げます。
ホームページのご提案もさせていただいております

忘備録, PHP

Posted by OBATA