printf("日本語");
などと、printf()
で日本語を扱うことには違和感があるが、
実際、使えると非常に便利。
「ANSI規格ではpritnf()
で日本語は使えないんだぞ」などと言っても、
じゃぁ日本語はどうやって書くんだと言われるとよく知らない。
なので、ちょっと調べて整理します。
種類 | 型 | 使える文字列処理の関数 | 説明 |
---|---|---|---|
1Byte文字 | charを使う | str系の関数を使う | C言語では普通キャラクタというと、これになる。 ASCII文字とよく言うが、厳密には日本人が使ってる文字コードでは バックスラッシュがエンマークになってるのでASCIIコードじゃない。(JIS X0201だっけ?) ASCIIというのはちょっと変かも。 |
2Byte文字 | wchar_tを使う | wの付いてる関数 | 漢字を2Byteで表現するから2Byte文字と呼んでる。 UNICODEはこれで表現するらしい。 処理系によってはwcharは4byteの場合もあるので、2Byte文字=wchar_tというのはおかしいが、まぁ、そんなものとだけ覚えている。 これを みるかぎり、wcahr_tを使ったプログラムでUNICODEしか考えてなく、localeがまともに機能しない プログラムがあるらしい。 |
マルチバイト文字 | charと言いたいところだが、charを複数個使って1文字を表すのでchar*というべきか? | mbの付いてる関数 | 複数Byteで1文字を表す。
日本語は2Byteしか使わないと思いがちだが、実はEUCコードには3Byte文字もある。
と、いってもEUCにはEUC-JP,eucJP-open,eucJP-ms,CP51932など種類があるらしく、
普段EUCだと思って使ってるLocaleはEUC-JPでは3Byte文字は使わないらしい.(本当か?)
文字列としては、1byte文字とまぜて使う場合があるので、固定Byte数とはならない。
なので、文字列を走査するプログラムを書くときに、1文字後ろを読むつもりでポインタを2Byte後にずらして読むと
2文字後の場合や2Byte文字の後ろ半分Byteにポインタが移動してしまい、とんでもないことになる。
1byte文字だったら当たり前だったs[i]= '\0' とかif(s[i]=='-') なんて記述ができない。
mb系の関数は、標準のCにはない。(あってもwcharと変換する関数くらいで、まともに使える状況ではない)。
|
ジェネリック文字 | TCHARを使う。これ、実はマクロ。defineされている内容に応じてcharやwchar_tに化ける | _tの付いてる関数 | TCHARというマクロをつかう。TCHARは処理系や定義にあわせて上記3つのどれかに切り替えてコンパイルしてくれる。
VC++依存になるので、Windowsしか使えない。
文字列も_T("文字列") のように_T() マクロを使って表現する。
文字列操作もジェネリックテキストの関数(といってもマクロ?)を使う。
ジェネリックテキストを使う関数への表を見ながらじゃないと関数名が判らず、使いこなせない。
|
p++
のようにインクリメントで1文字ずらすのがイディオムになっているが、
tchar
ではこの方法が使えずp = _tcsinc(p)
のように関数を使う。p = _tcsdec(start, p)
のように文字列の先頭のポインタも指定しないと使えない。_tccmp(a, b)
を使います。if(*a == *b)
と書けたものが、
if(_tccmp(a,b) == 0)
になります。
_tccpy(a, b)
を使います。*a = *b
は
_tccpy(a,b)
になります。
また、
*a = 'b'
は
_tccpy(a,"b")
になります。
また、
*a = '\\'
は
_tccpy(a,"\\")
、
*a = '\0'
は
_tccpy(a,"")
となります。
これが気持ち悪い!。でもしょうがない。
char だったら p[x] = 'z'
とかけたが、マルチバイトだと難しい。
_tcsinc()
で文字を動かしてから、_tccpy()
を使うなんて方法が思いつくが、
これじゃだめ。
書き換える前の文字が1byteなのに2byte文字を書いたとか、その逆をやってしま可能性があるから。
無理やりやるとしたら、書き換えたい文字のところで文字列を区切り、
「書き換えたい文字の前の文字まで」+「書き換える文字」+「書き換えた文字から文字列の最後まで」の
3つをつないだ文字列を別に作ることになる。
操作する文字のbyte数の違いに起因する問題に引っかからない為の考え方としては、 マルチバイト文字列(ジェネリック文字列も)を扱っている時は、1文字を操作するという考えではなく、 文字列を操作するつもりで考え、その対象の文字列長が1だっただけとみなすのが良いでしょう。
_tcsnccpy()
があるので、
これでコピーした後、気をつけてnullをつける。
fp = _tfopen(_T("日本語ファイル.txt"),_T("w"))
と使う。
fclose()
はtが付かない。
_tprintf(_T("日本語"));
とか_ftprintf(stderr, _T("日本語"));
てなかんじ