増永 玲 さんが、おー、となるライブラリを作ってはって、確かにたまに知りたいけど見なかったことにしてる所だなぁ、と思った。と同時に別のことでちょっと気になったこと。
玲さんが作られたライブラリとは全く関係ありませんよっと。そんで眠たいので雑。
ややこしいことに PHP でサポートされる文字エンコーディングにはエイリアスがあって SJIS の場合は Shift_JIS, SHIFT-JIS, x-sjis と それぞれの大文字小文字違いも同じ扱いなので そのへんを isSjis() というメソッドのあたりで処理してます。
の x-sjis と SHIFT-JIS と Shift_JIS の扱いがそれぞれ大文字小文字違いも同じ扱いってのが少し気になって、Pythonでも CP932
と shift_jisx0213
とか微妙な差はあったはずよなぁ、と思ったのです。で、実際 Shift_JIS と SHIFT-JIS はどやつを見てるのかしらと気になるわけでしす。
で、こーいうのはドキュメントよりソース見たほうが速いっつー事で見て行ったら、libmbflってのに行き着くわけで、さぁどうなってるかな、と。
とりあえず PHP から見える、対応しているエンコード一覧はこんな感じ。
php-shell
php > print_r(mb_list_encodings());
Array
(
[0] => pass
[1] => auto
[2] => wchar
...
[30] => SJIS
[31] => eucJP-win
[32] => SJIS-win
[33] => CP932
[35] => JIS
[36] => ISO-2022-JP
[37] => ISO-2022-JP-MS
[38] => Windows-1252
[39] => Windows-1254
[40] => ISO-8859-1
ではでは、ソース見学。ざっと見たところ「mbfl_name2encoding」っていう関数がエンコード名解決をしている気配。
サンプルとして、mb_convert_encoding の実態
php-src/ext/mbstirng/mbstring.c
2948 MBSTRING_API char * php_mb_convert_encoding(const char *input, size_t length, const char *_to_encoding, const char *_from_encodings, si ze_t *output_len TSRMLS_DC)
...
2963 /* new encoding */
2964 if (_to_encoding && strlen(_to_encoding)) {
2965 to_encoding = mbfl_name2encoding(_to_encoding);
2966 if (!to_encoding) {
2967 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", _to_encoding);
2968 return NULL;
2969 }
2970 } else {
2971 to_encoding = MBSTRG(current_internal_encoding);
2972 }
で、だ、「mbfl_name2encoding」はというと、
php-src/ext/mbstirng/libmbfl/mbfl/mbfl_encoding.c
133 static const mbfl_encoding *mbfl_encoding_ptr_list = {
134 &mbfl_encoding_pass,
135 &mbfl_encoding_auto,
136 &mbfl_encoding_wchar,
137 &mbfl_encoding_byte2be,
138 &mbfl_encoding_byte2le,
...
167 &mbfl_encoding_sjis_open,
168 &mbfl_encoding_sjis_docomo,
169 &mbfl_encoding_sjis_kddi,
170 &mbfl_encoding_sjis_sb,
171 &mbfl_encoding_sjis_mac,
172 &mbfl_encoding_sjis2004,
173 &mbfl_encoding_utf8_docomo,
174 &mbfl_encoding_utf8_kddi_a,
175 &mbfl_encoding_utf8_kddi_b,
176 &mbfl_encoding_utf8_sb,
177 &mbfl_encoding_cp932,
178 &mbfl_encoding_cp51932,
179 &mbfl_encoding_jis,
180 &mbfl_encoding_2022jp,
...
210 &mbfl_encoding_koi8r,
211 &mbfl_encoding_koi8u,
212 &mbfl_encoding_armscii8,
213 &mbfl_encoding_cp850,
214 &mbfl_encoding_jis_ms,
215 &mbfl_encoding_2022jp_2004,
216 &mbfl_encoding_2022jp_kddi,
217 &mbfl_encoding_cp50220,
218 &mbfl_encoding_cp50220raw,
219 &mbfl_encoding_cp50221,
220 &mbfl_encoding_cp50222,
221 NULL
222 };
...
226 mbfl_name2encoding(const char *name)
227 {
228 const mbfl_encoding *encoding;
229 int i, j;
230
231 if (name == NULL) {
232 return NULL;
233 }
234
235 i = 0;
236 while ((encoding = mbfl_encoding_ptr_list[i++]) != NULL){
237 if (strcasecmp(encoding->name, name) == 0) {
238 return encoding;
239 }
240 }
241
242 /* serch MIME charset name */
243 i = 0;
244 while ((encoding = mbfl_encoding_ptr_list[i++]) != NULL) {
245 if (encoding->mime_name != NULL) {
246 if (strcasecmp(encoding->mime_name, name) == 0) {
247 return encoding;
248 }
249 }
250 }
251
252 /* serch aliases */
253 i = 0;
254 while ((encoding = mbfl_encoding_ptr_list[i++]) != NULL) {
255 if (encoding->aliases != NULL) {
256 j = 0;
257 while ((*encoding->aliases)[j] != NULL) {
258 if (strcasecmp((*encoding->aliases)[j], name) == 0) {
259 return encoding;
260 }
261 j++;
262 }
263 }
264 }
265
266 return NULL;
267 }
長ったらしいけど仕方ない。
さてさて、ここで比較されているのは「mbfl_encoding_ptr_list」の値。比較には「strcasecmp」関数使われているので、大文字小文字は関係なしになってますね。これで疑問一つ解消。 では「mbfl_encoding_ptr_list」とはというと、上でconstで定期されてますねっと。こやつ、殆ど PHPの「mb_list_encodings」関数の返り値と似てます。
で、だ、この「mbfl_encoding_ptr_list」の中にある構造体は「mbfl_encoding」という構造体らしく、こやつの要素はこんな感じ。
php-src/ext/mbstirng/libmbfl/mbfl/mbfl_encoding.h
134 typedef struct _mbfl_encoding {
135 enum mbfl_no_encoding no_encoding;
136 const char *name;
137 const char *mime_name;
138 const char *(*aliases);
139 const unsigned char *mblen_table;
140 unsigned int flag;
141 } mbfl_encoding;
flagっつーのが何なのかわからないけど、まぁ大体わかりますよね?nameが実際名、aliases がエイリアス名、mime_name が通変的な名前?
で、実際にはこんな感じで使われてる。
php-src/ext/mbstirng/libmbfl/filters/mbfilter_cp932.c
61 static const char *mbfl_encoding_cp932_aliases = {"MS932", "Windows-31J", "MS_Kanji", NULL};
62
63 const mbfl_encoding mbfl_encoding_cp932 = {
64 mbfl_no_encoding_cp932,
65 "CP932",
66 "Shift_JIS",
67 (const char *(*))&mbfl_encoding_cp932_aliases,
68 mblen_table_sjis,
69 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
70 };
C の構造体を見るのがかなり久しぶりで、こういう書き方だっけな、という状態ですが、まぁ、コレだと「name->CP932」「mime_name->Shift_JIS」「aliases -> {"MS932", "Windows-31J", "MS_Kanji", NULL}」
で、だ、「SJIS, Shift_JIS, SHIFT-JIS, x-sjis」それぞれ違いはと、いう話なんですが、sjisの処理系は5つに分かれておりまして、mbfilter_(cp932|sjis|sjis_2004|sjis_mac|sjis_mobile|sjis_open) となっておりますよっと。
それぞれ必要部分だけ書きだしてみるとこんな感じ
php-src/ext/mbstirng/libmbfl/filters/mbfilter_cp932.c
61 static const char *mbfl_encoding_cp932_aliases = {"MS932", "Windows-31J", "MS_Kanji", NULL};
62
63 const mbfl_encoding mbfl_encoding_cp932 = {
64 mbfl_no_encoding_cp932,
65 "CP932",
66 "Shift_JIS",
67 (const char *(*))&mbfl_encoding_cp932_aliases,
68 mblen_table_sjis,
69 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
70 };
php-src/ext/mbstirng/libmbfl/filters/mbfilter_sjis.c
64 static const char *mbfl_encoding_sjis_aliases = {"x-sjis", "SHIFT-JIS", NULL};
65
66 const mbfl_encoding mbfl_encoding_sjis = {
67 mbfl_no_encoding_sjis,
68 "SJIS",
69 "Shift_JIS",
70 (const char *(*))&mbfl_encoding_sjis_aliases,
71 mblen_table_sjis,
72 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
73 };
php-src/ext/mbstirng/libmbfl/filters/mbfilter_sjis_2004.c
48 static const char *mbfl_encoding_sjis2004_aliases = {"SJIS2004","Shift_JIS-2004", NULL};
49
50 const mbfl_encoding mbfl_encoding_sjis2004 = {
51 mbfl_no_encoding_sjis2004,
52 "SJIS-2004",
53 "Shift_JIS",
54 (const char *(*))&mbfl_encoding_sjis2004_aliases,
55 mblen_table_sjis,
56 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
57 };
php-src/ext/mbstirng/libmbfl/filters/mbfilter_sjis_mac.c
47 static const char *mbfl_encoding_sjis_mac_aliases = {"MacJapanese", "x-Mac-Japanese", NULL};
48
49 const mbfl_encoding mbfl_encoding_sjis_mac = {
50 mbfl_no_encoding_sjis_mac,
51 "SJIS-mac",
52 "Shift_JIS",
53 (const char *(*))&mbfl_encoding_sjis_mac_aliases,
54 mblen_table_sjis,
55 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
56 };
php-src/ext/mbstirng/libmbfl/filters/mbfilter_sjis_mobile.c
47 static const char *mbfl_encoding_sjis_docomo_aliases = {"SJIS-DOCOMO", "shift_jis-imode", "x-sjis-emoji-docomo", NULL};
48 static const char *mbfl_encoding_sjis_kddi_aliases = {"SJIS-KDDI", "shift_jis-kddi", "x-sjis-emoji-kddi", NULL};
49 static const char *mbfl_encoding_sjis_sb_aliases = {"SJIS-SOFTBANK", "shift_jis-softbank", "x-sjis-emoji-softbank", NULL};
50
51 const mbfl_encoding mbfl_encoding_sjis_docomo = {
52 mbfl_no_encoding_sjis_docomo,
53 "SJIS-Mobile#DOCOMO",
54 "Shift_JIS",
55 (const char *(*))&mbfl_encoding_sjis_docomo_aliases,
56 mblen_table_sjis,
57 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
58 };
59
60 const mbfl_encoding mbfl_encoding_sjis_kddi = {
61 mbfl_no_encoding_sjis_kddi,
62 "SJIS-Mobile#KDDI",
63 "Shift_JIS",
64 (const char *(*))&mbfl_encoding_sjis_kddi_aliases,
65 mblen_table_sjis,
66 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
67 };
68
69 const mbfl_encoding mbfl_encoding_sjis_sb = {
70 mbfl_no_encoding_sjis_sb,
71 "SJIS-Mobile#SOFTBANK",
72 "Shift_JIS",
73 (const char *(*))&mbfl_encoding_sjis_sb_aliases,
74 mblen_table_sjis,
75 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
76 };
php-src/ext/mbstirng/libmbfl/filters/mbfilter_sjis_open.c
61 static const char *mbfl_encoding_sjis_open_aliases = {"SJIS-open", "SJIS-ms", NULL};
62
63 const mbfl_encoding mbfl_encoding_sjis_open = {
64 mbfl_no_encoding_sjis_open,
65 "SJIS-win",
66 "Shift_JIS",
67 (const char *(*))&mbfl_encoding_sjis_open_aliases,
68 mblen_table_sjis,
69 MBFL_ENCTYPE_MBCS | MBFL_ENCTYPE_GL_UNSAFE
70 };
長ったらしいです。ですがフォーマットが統一されているので、いいですよね?
さてさて、「mbfl_name2encoding」の処理を見ると、
- 「mbfl_encoding_ptr_list」を一から見て、中の name を見て比較、ありゃ返す
- 「mbfl_encoding_ptr_list」を一から見て、中の MIME を見て比較、ありゃ返す
- 「mbfl_encoding_ptr_list」を一から見て、中のエイリアスを見て比較、ありゃ返す。
- 見つからん時は NULL
で、「mbfl_encoding_ptr_list」はというと、上記に書いた感じで順番に並んでます。
Shift-jis 周りだけを見るとこんな感じ
php-src/ext/mbstirng/libmbfl/mbfl/mbfl_encoding.c
164 &mbfl_encoding_sjis,
...
167 &mbfl_encoding_sjis_open,
168 &mbfl_encoding_sjis_docomo,
169 &mbfl_encoding_sjis_kddi,
170 &mbfl_encoding_sjis_sb,
171 &mbfl_encoding_sjis_mac,
172 &mbfl_encoding_sjis2004,
...
177 &mbfl_encoding_cp932,
そんなわけで
- 「Shift-JIS」と銘打った場合、「mbfl_name2encoding」の処理手順から見て、エイリアスに「SHIFT-JIS」がある「SJIS」(mbfl_encoding_sjis)と等価になります。
- 「Shift_JIS」と銘打った場合、「mbfl_name2encoding」の処理手順から見て、MIMEに当てはまるので「SJIS」と等価になります。
- 「x-sjis」と銘打った(ry
そんな訳で、パフォーマンスの差はありますが、「SJIS, Shift_JIS, SHIFT-JIS, x-sjis」は変換する文字コードの種類は同じです。
ちょっとでもパフォーマンスが気になる、という人は「Shift-JIS」や「Shift_JIS」や「x-sjis」を「SJIS」に変換して投げてやればいいと思うんです。
そんじゃーね