- 文字化け
-
D言語 で コンソールアプリ を組む場合、日本語の文字化け問題を解決する必要があります。
「日本語表示を諦める」という解決方法もありだと思いますが、日本語表示が出来ない コンソールアプリ ではさすがに面白みに欠けます。
- 文字コード
-
文字列 の表示には、それぞれの 文字 の形を表示しますから、多彩な表示のためにはより多くの 文字キャラクタ が必要になり、その 割り当て を決める必要もあります。
文字コード というのは 文字キャラクタコード のことで、その 割り当て を決めた 規格 そのものを指したりもします。
- ASCIIコード
-
0 から 0x7F( 0 - 127 )の値に英数字、記号及び制御コードを割り当てた規格。
もちろん 英数字と記号にも ASCIIコード 以外の規格はありますし、汎用コンピューターでなければ独自のコード割り当てもありです。
また、ASCIIコード は 7ビット に収まっていて 1バイト の後ろ半分( 0x80 から 0xFF )が未使用なので、ASCIIコード はそのままに 未使用部分だけ を使って拡張しているのが UTF-8 などの文字コードです。
「ASCIIコード表」を検索すればありますが、制御コード以外を見るのは簡単です。体裁をいくらか考えて、
import std.stdio; /*---------------------------- * 数値 n を 整形して出力 * * 10進数( 16進数 ) : 文字 */ void toAscii( in int n, in string s = " " ){ // 0 - 0x1F の制御コードの表示は NG writef( "%s%3d( 0x%02x ) : %s", s, n, n, cast( char )n ); } /***************************** * * ASCII コード表 */ void main(){ writeln( " ---- ASCII Code ----\n" " 0 - 31( 0x1F ) : control code" ); foreach( i; 0x20 .. 0x80 ){ if( i % 4 ){ toAscii( i ); } else{ toAscii( i, "\n" ); } } writeln(); }
D:\Pen-Jr\My Programs\supp>test ---- ASCII Code ---- 0 - 31( 0x1F ) : control code 32( 0x20 ) : 33( 0x21 ) : ! 34( 0x22 ) : " 35( 0x23 ) : # 36( 0x24 ) : $ 37( 0x25 ) : % 38( 0x26 ) : & 39( 0x27 ) : ' 40( 0x28 ) : ( 41( 0x29 ) : ) 42( 0x2a ) : * 43( 0x2b ) : + 44( 0x2c ) : , 45( 0x2d ) : - 46( 0x2e ) : . 47( 0x2f ) : / 48( 0x30 ) : 0 49( 0x31 ) : 1 50( 0x32 ) : 2 51( 0x33 ) : 3 52( 0x34 ) : 4 53( 0x35 ) : 5 54( 0x36 ) : 6 55( 0x37 ) : 7 56( 0x38 ) : 8 57( 0x39 ) : 9 58( 0x3a ) : : 59( 0x3b ) : ; 60( 0x3c ) : < 61( 0x3d ) : = 62( 0x3e ) : > 63( 0x3f ) : ? 64( 0x40 ) : @ 65( 0x41 ) : A 66( 0x42 ) : B 67( 0x43 ) : C 68( 0x44 ) : D 69( 0x45 ) : E 70( 0x46 ) : F 71( 0x47 ) : G 72( 0x48 ) : H 73( 0x49 ) : I 74( 0x4a ) : J 75( 0x4b ) : K 76( 0x4c ) : L 77( 0x4d ) : M 78( 0x4e ) : N 79( 0x4f ) : O 80( 0x50 ) : P 81( 0x51 ) : Q 82( 0x52 ) : R 83( 0x53 ) : S 84( 0x54 ) : T 85( 0x55 ) : U 86( 0x56 ) : V 87( 0x57 ) : W 88( 0x58 ) : X 89( 0x59 ) : Y 90( 0x5a ) : Z 91( 0x5b ) : [ 92( 0x5c ) : \ 93( 0x5d ) : ] 94( 0x5e ) : ^ 95( 0x5f ) : _ 96( 0x60 ) : ` 97( 0x61 ) : a 98( 0x62 ) : b 99( 0x63 ) : c 100( 0x64 ) : d 101( 0x65 ) : e 102( 0x66 ) : f 103( 0x67 ) : g 104( 0x68 ) : h 105( 0x69 ) : i 106( 0x6a ) : j 107( 0x6b ) : k 108( 0x6c ) : l 109( 0x6d ) : m 110( 0x6e ) : n 111( 0x6f ) : o 112( 0x70 ) : p 113( 0x71 ) : q 114( 0x72 ) : r 115( 0x73 ) : s 116( 0x74 ) : t 117( 0x75 ) : u 118( 0x76 ) : v 119( 0x77 ) : w 120( 0x78 ) : x 121( 0x79 ) : y 122( 0x7a ) : z 123( 0x7b ) : { 124( 0x7c ) : | 125( 0x7d ) : } 126( 0x7e ) : ~ 127( 0x7f ) : - Unicode
-
英数字と記号だけでなく、世界中の文字を符号化( 数値化 )する規格。
16ビット( 0 - 0xFFFF )に納めた規格( UTF-16 )と、32ビット( 0 - 0xFFFF_FFFF )の規格( UTF-32 )がありますが、いずれも各々の国の文化などはほぼ考慮されてはいませんから、最近流行の書籍のデジタルが Unicode なのは問題でしょうが、普通問題になるような欠落があるわけではないと思います。
- UTF-8
-
Unicode 文字 を 可変長のバイト値( 8ビット値 )に変換する規格で、
日本語の文字の多くは 3バイト 以上になりますから日本語の文章などでは不利ですが、ASCII 文字 は 1バイト で済みますから、プログラムコード などの英数字や記号が多いテキストには有利。
また、可変長 と言うことで UTF-16 より表現力があるらしいです。
- UTF-16
-
全て 2バイト( 16ビット )の規格。
Windows( Win32API )の Unicode は UTF-16 です。
-
UTF-8とShift-JIS -
Unicodeな D が 日本語で文字化けするのはShift-JISとの違いが原因なわけですが、比較すると、
import std.stdio, std.windows.charset, std.conv; /***************************** * 文字列 s のコード表示 */ void dispArray( in string nam, in string s ){ writef( "%s = [\n ", nam ); foreach( i, c; s ){ if( i ){ // 一行の幅を制限する if( i % 10 ){ write( ", " ); } else{ write( "\n " ); } } // charをubyteに変換して16進数表示する writef( "0x%02x", cast( ubyte )c ); } writeln( "\n ]" ); } /***************************** * * 引数文字列のエンコード比較 */ void main( in string[] args ){ foreach( i, s; args[ 1 .. $ ] ){ if( i ) writeln(); // Shift-JIS に変換 auto sj = to!string( toMBSz( s ) ); writefln( " %s( %s )", sj, s ); dispArray( "UTF-8", s ); dispArray( "Shif-JIS", sj ); } }
D:\Pen-Jr\My Programs\supp>test abcABC012!@# D言語の文字化け abcABC012!@#( abcABC012!@# ) UTF-8 = [ 0x61, 0x62, 0x63, 0x41, 0x42, 0x43, 0x30, 0x31, 0x32, 0x21 0x40, 0x23 ] Shif-JIS = [ 0x61, 0x62, 0x63, 0x41, 0x42, 0x43, 0x30, 0x31, 0x32, 0x21 0x40, 0x23 ] D言語の文字化け( ・、險隱槭・譁・ュ怜喧縺・) UTF-8 = [ 0xef, 0xbc, 0xa4, 0xe8, 0xa8, 0x80, 0xe8, 0xaa, 0x9e, 0xe3 0x81, 0xae, 0xe6, 0x96, 0x87, 0xe5, 0xad, 0x97, 0xe5, 0x8c 0x96, 0xe3, 0x81, 0x91 ] Shif-JIS = [ 0x82, 0x63, 0x8c, 0xbe, 0x8c, 0xea, 0x82, 0xcc, 0x95, 0xb6 0x8e, 0x9a, 0x89, 0xbb, 0x82, 0xaf ]なぜ コマンドライン引数 が
UTF-8なのかいまいちよくわかりませんが、Shift-JISとUTF-8では ASCIIコード 部分は同じ様ですが、日本語コードにはかなりの違いがあります。特に サイズ がかなり違うのというのはどうゆうこちゃねん、と
- Shift-JIS が糞(確)
-
サイズがコンパクトで優秀なふりをするのはその経緯を見ればいかにもな感じですが、何気に選んだ日本語にもすでにあるはずがないコードがあったりします。
ASCIIコード というのは
0から0x7Fに英数字と記号、制御コードが割り振られていて、0x80から0xFFは使っていませんから、ASCIIコード が同じで、その未使用領域だけを使って拡張していれば ASCIIコード の解析には問題がないのですが、Shift-JIS は、
import std.stdio, std.windows.charset, std.conv; /***************************** * c が ASCIIコードなら * その文字を返す */ char isAscii( in char c ){ if( c < 0x80 ) return c; return ' '; } /***************************** * 文字列 s のコード表示 */ void dispArray( in string s ){ writef( "%s = [\n ", s ); foreach( i, c; s ){ if( i ){ if( i % 6 ){ write( ", " ); } else{ write( "\n " ); } } // 文字コード表示とASCIIコードチェック writef( "0x%02x( %s )", cast( ubyte )c, isAscii( c ) ); } writeln( "\n ]" ); } /***************************** * */ void main( in string[] args ){ foreach( i, s; args[ 1 .. $ ] ){ writeln(); dispArray( to!string( toMBSz( s ) ) ); } }
D:\Pen-Jr\My Programs\supp>test abcABC012!@# 暴力 表示+ abcABC012!@# = [ 0x61( a ), 0x62( b ), 0x63( c ), 0x41( A ), 0x42( B ), 0x43( C ) 0x30( 0 ), 0x31( 1 ), 0x32( 2 ), 0x21( ! ), 0x40( @ ), 0x23( # ) ] 暴力 表示+ = [ 0x96( ), 0x5c( \ ), 0x97( ), 0xcd( ), 0x81( ), 0x40( @ ) 0x95( ), 0x5c( \ ), 0x8e( ), 0xa6( ), 0x81( ), 0x7b( { ) ]英数字だけならまだしも、記号まで使ってやがります。
UTF-8 表示のところに Shift-JIS を渡すと、文字化け 程度では済まないというわけで、特に 解析 は間違えなく失敗します。
要するに、Shift-JIS に変換してから、UTF-8 を扱う Phobos に渡すのは 間違い なわけなのですが、 - 糞を渡しても転けない?
- std.utf( Phobos )
-
- エンコード
-
string toUTF8( in char[] s ); string toUTF8( in wchar[] s ); string toUTF8( in dchar[] s );
wstring toUTF16( in char[] s ); const( wchar )* toUTF16z( in char[] s ); wstring toUTF16( in wchar[] s ); wstring toUTF16( in dchar[] s );
dstring toUTF32( in char[] s ); dstring toUTF32( in wchar[] s ); dstring toUTF32( in dchar[] s );
import std.stdio, std.utf; /***************************** * wcharの文字コード表示 */ void dispCode( in wchar[] code ){ write( "[ " ); foreach( i, c; code ){ if( i ) write( ", " ); writef( "0x%04x", cast( uint )c ); } writeln( " ]" ); } /***************************** * * */ void main(){ string s = "文字コードの変換"; dispCode( toUTF16( s ) ); // ソースコードはUTF-8 wstring ws = "文字コードの変換"; dispCode( ws ); dispCode( "文字コードの変換" ); // これじゃ無理かな? writeln(); dispCode( cast( wstring )s ); }
D:\Pen-Jr\My Programs\supp>test [ 0x6587, 0x5b57, 0x30b3, 0x30fc, 0x30c9, 0x306e, 0x5909, 0x63db ] [ 0x6587, 0x5b57, 0x30b3, 0x30fc, 0x30c9, 0x306e, 0x5909, 0x63db ] [ 0x6587, 0x5b57, 0x30b3, 0x30fc, 0x30c9, 0x306e, 0x5909, 0x63db ] [ 0x96e6, 0xe587, 0x97ad, 0x82e3, 0xe3b3, 0xbc83, 0x83e3, 0xe389, 0xae81, 0xa4e5 , 0xe689, 0x9b8f ]
- 文字数
-
size_t toUCSindex( in char[] s, size_t i ); size_t toUCSindex( in wchar[] s, size_t i ); size_t toUCSindex( in dchar[] s, size_t i );
size_t count( E )( const( E )[] s );
- Phobos( 標準ライブラリ )
-
- 正規表現
- 式( Expressions )
- 型( Types )
-
- 配列
- ポインタ
-
別名宣言(
alias) -
構造体・共用体(
struct & union) - 連想配列( Associative Arrays )
-
クラス(
class)
- 属性( Attributes )
- 制御文( Statements )
- 関数
