前回に引き続き、PHPのmb_check_encoding関数について調べてみます。今回はEUC-JP、eucJP-win、CP51932の3つについて調べてみました。
EUC-JP
EUC-JPというのは0xA1から0xFEまでの2バイトの組み合わせでJISX0208漢字(いわゆるJIS第一水準&第二水準)を、SS2(0x8E)からはじまる2バイトでJISX0201カナ(いわゆる半角カナ)を、SS3(0x8F)からはじまる3バイトでJISX0212補助漢字を、それぞれ表現するようなエンコーディング形式です。
EUC-JPに対するmb_check_encodingの挙動はシンプルで、次のものがtrueになります。
- 0xA1A1(JISX0208 1区1点)から0xFEFE(JISX0208 94区94点)まで
- 0x8EA1(半角カナの句点「。」)から0x8EDF(半角カナの半濁点「゜」)まで
- 0x8EE0から0x8EFEまではfalseとなりますが、他との整合性の意味で疑問です。字体が定義されていないのでfalseということなら、字体が未定義なのにtrueになる文字が他に多数あるので、ここだけfalseにするのは微妙な気がします。
- 0x8FA1A1(JISX0212 1区1点)から0x8FFEFE(JISX0212 94区94点)まで
- ただし、0x8FA2B7のみfalse。これは全角チルダ「〜」であり、重複文字であるため。
これ以外のパターンは全てfalseとなります。つまり、次のような場合は全て不正な文字列として扱われます。
- 1byteでは存在し得ない文字で終わっている文字列。つまり、1byte文字または2byte文字に続いて0x80から0xFFまでの1byteがある場合。
- 2byte文字の1byte目に続いて2byte目には有り得ない1byteが続く場合。0xA1 0xA0など。
- 3byte文字の1byte目に続いて2byte目には有り得ない1byteが続く場合。0x8F 0xA0 0xA1など。
- 3byte文字の1byte目&2byte目に続いて3byte目には有り得ない1byteが続く場合。0x8F 0xA1 0xA0など。
eucJP-win
eucJP-winというのは、EUC-JPに加えてIBM拡張文字やら何やらを含んでるもの、というくらいの認識で良いかと思います。SJIS-winのEUC版、くらいに考えておけば大抵は問題ないでしょう。
具体的には、JISX0208の13区にNEC特殊文字、JISX0212の83区から84区にIBM拡張文字の一部が割り当てられていること、またユーザ定義文字領域としてJISX0208の85区から94区、およびJISX0212の85区から94区までを割り当てているのが違いになります。詳しくは森山さんのページ「eucJP-ms」を参照してください。
mb_check_encodingの挙動は、EUC-JPに比べて下記の文字が余計に不正と見なされます。
- NEC特殊文字の9文字
- 0xADF0(≒), 0xADF1(≡), 0xADF2(∫), 0xADF5(√), 0xADF6(⊥), 0xADF7(∠), 0xADFA(∵), 0xADFB(∩), 0xADFC(∪)
- IBM拡張文字の13文字
- 0x8FF3FDから0x8FF3FE(ローマ数字のIとII)
- 0x8FF4A1から0x8FF4A8(ローマ数字のIIIからX)
- 0x8FF4AB (株)
- 0x8FF4AC No.
- 0x8FF4AD TEL
- 0x8FA2F1(補助漢字2区の「No.」)
これらの文字は全て代替の文字があるためfalseになります。これは望ましい動作かどうかは疑問ですが、現在の仕様としては理解できる挙動です。さらに、これとは別に次の文字もfalseを返します。
半角カナと同様、字体が割り当てられていないからといってfalseを返すのは疑問に思います。
CP51932
CP51932というのは、Microsoft製品の理解するEUC-JP、くらいの認識で良いと思います。IEなどが理解するEUC-JPというのは、UNIXの世界でよく使われているEUC-JPとは少し違うんだそうです。
EUC-JPとの具体的な違いは下記の通りです。これも詳しくは森山さんの記事「eucJP-ms と CP51932 の違い」を参照するのがいいと思います。
mb_check_encodingの挙動は、EUC-JPのときの挙動に対して、下記の文字でfalseを返します。
まとめ
前回の記事を書いた後のやりとりで、mb_check_encoding関数ってあまり使いどころが無いのかな、と感じるようになりました。不正な文字がないかどうかのチェックをしたいのであれば、重複文字を不正とみなすのは致命的です。
もちろん、UTF-8などUnicode系のエンコーディングのチェックにはmb_check_encodingは活躍すると思います。Unicode同士であれば重複文字はありませんし、実験した範囲では、冗長なUTF-8表現など、不正なUTF-8をちゃんと検出するようです。
また、今回の調査結果からすると、EUC-JPまたはeucJP-winの正当性のチェックにならmb_check_encoding($str, "EUC-JP")が使えそうですね。補助漢字の「〜」を誤判定しますけど、この文字を作り出すのって結構難しいんじゃないでしょうか。まあ、それを言い出したらSJIS-winでも重複文字を作るのは難しいかもしれませんが…。