文字エンコーディング判定スクリプト
最近、忙しかったのですが、久しぶりに少し時間があったので、随分前に書いた文字エンコーディング判定スクリプトを見直してみました。とりあえず、出来上がったものを投稿しておきます。
何か適当な日本語の文字列を与えると、JIS/eucJP-win/SJIS-win/UTF-8 からそれなりに妥当な文字エンコーディングを返します。短い文字列で、mb_detect_encoding() だけでは判定に失敗する場合に役立つかもしれません。PHP 5.2.12 での動作を確認しています。
<?php /** * 日本語文字列の文字エンコーディング判定(ASCII/JIS/eucJP-win/SJIS-win/UTF-8) */ function detect_encoding_ja( $str ) { $enc = mb_detect_encoding( $str, 'ASCII,JIS,eucJP-win,SJIS-win,UTF-8', TRUE ); switch ( $enc ) { case FALSE : case 'ASCII' : case 'JIS' : case 'UTF-16' : case 'UTF-8' : break; case 'eucJP-win' : // ここで eucJP-win を検出した場合、eucJP-win として判定 if ( mb_detect_encoding( $str, 'SJIS-win,UTF-8,eucJP-win', TRUE ) === 'eucJP-win' ) { break; } $_hint = "\xbf\xfd" . $str; // "\xbf\xfd" : EUC-JP "雀" // EUC-JP -> UTF-8 変換時にマッピングが変更される文字を削除( ≒ ≡ ∫ など) mb_regex_encoding( 'eucJP-win' ); $_hint = mb_ereg_replace( "\xad[\xe2\xf5\xf6\xf7\xfa\xfb\xfc\xf0\xf1\xf2\xf5\xf6\xf7\xfa\xfb\xfc]|" . "\x8f\xf3[\xfd\xfe]|\x8f\xf4[\xa1-\xa8\xab\xac\xad]|\x8f\xa2\xf1", '', $_hint ); $_tmp = mb_convert_encoding( $_hint, 'UTF-8', 'eucJP-win' ); $_tmp2 = mb_convert_encoding( $_tmp, 'eucJP-win', 'UTF-8' ); if ( $_tmp2 === $_hint ) { // 例外処理( EUC-JP 以外と認識する範囲 ) if ( // SJIS と重なる範囲(2バイト|3バイト|iモード絵文字|1バイト文字) ! preg_match( '/^(?:' . '(?:[\x8e\xe0-\xe9][\x80-\xfc])+|' . '(?:\xea[\x80-\xa4])+|' . '(?:\x8f[\xb0-\xef][\xe0-\xef][\x40-\x7f])+|' . '(?:\xf8[\x9f-\xfc])+|' . '(?:\xf9[\x40-\x49\x50-\x52\x55-\x57\x5b-\x5e\x72-\x7e\x80-\xb0\xb1-\xfc])+|' . '[\x00-\x7e]+' . ')+$/', $str ) && // UTF-8 と重なる範囲(全角英数字・記号|漢字|1バイト文字) ! preg_match( '/^(?:' . '(?:\xef[\xbc-\xbd][\x80-\xbf])+|(?:\xef\xbe[\x80-\x9f])+|(?:\xef\xbf[\xa0-\xa5])+|' . '(?:[\xe4-\xe9][\x8e-\x8f\xa1-\xbf][\x8f\xa0-\xef])+|' . '[\x00-\x7e]+' . ')+$/', $str ) ) { // 条件式の範囲に入らなかった場合は、eucJP-win として検出 break; } // 例外処理2(一部の頻度の多そうな熟語を eucJP-win として判定) // (狡猾|珈琲|琥珀|瑪瑙|碼碯|絨緞|耄碌|膃肭臍|薔薇|蜥蜴|蝌蚪) if ( preg_match( '/^(?:' . '\xe0\xc4\xe0\xd1|\xe0\xdd\xe0\xea|\xe0\xe8\xe0\xe1|\xe0\xf5\xe0\xef|' . '\xe2\xfb\xe2\xf5|\xe5\xb0\xe5\xcb|\xe6\xce\xe2\xf1|\xe9\xac\xe9\xaf|' . '\xe9\xf2\xe9\xee|\xe9\xf8\xe9\xd1|\xe7\xac\xe6\xed\xe7\xc1|' . '[\x00-\x7e]+' . ')+$/', $str ) ) { break; } } default : // ここで SJIS-win と判断された場合は、文字コードは SJIS-win として判定 $enc = mb_detect_encoding( $str, 'UTF-8,SJIS-win', TRUE ); if ( $enc === 'SJIS-win' ) { break; } $enc = 'SJIS-win'; // UTF-8 の記号と日本語の範囲の場合は UTF-8 として検出(記号|全角英数字・記号|漢字|1バイト文字) if ( preg_match( '/^(?:' . '(?:[\xc2-\xd4][\x80-\xbf])+|' . '(?:\xef[\xa4-\xab][\x80-\xbf])+|' . '(?:\xef[\xbc-\xbd][\x80-\xbf])+|' . '(?:\xef\xbe[\x80-\x9f])+|' . '(?:\xef\xbf[\xa0-\xa5])+|' . '(?:[\xe2-\xe9][\x80-\xbf][\x80-\xbf])+|' . '[\x09\x0a\x0d\x20-\x7e]+|' . ')+$/', $str ) ) { $enc = 'UTF-8'; } // UTF-8 と SJIS 2文字が重なる範囲への対処(SJIS を優先) if ( preg_match( '/^(?:[\xe4-\xe9][\x80-\xbf][\x80-\x9f][\x00-\x7f])+/', $str ) ) { $enc = 'SJIS-win'; } } return $enc; }
SJIS-win と UTF-8 が重なる部分の判定が難しいので、場合によってはうまく判定できない場合があります。
以下については、以前に書いた時と変わりません。