C 日本語文字列 新しいページはコチラ
提供: yonewiki
52行: | 52行: | ||
http://msdn.microsoft.com/ja-jp/library/x99tb11d(v=vs.90).aspx<br /> | http://msdn.microsoft.com/ja-jp/library/x99tb11d(v=vs.90).aspx<br /> | ||
<br /> | <br /> | ||
− | のようにsetlocale関数の記述が必要になります。setlocale関数を使うには#include<locale.h> | + | のようにsetlocale関数の記述が必要になります。setlocale関数を使うには#include<locale.h>が必要です。setlocale関数でも引数に文字列リテラルを与えるので、そこでワイド文字列を使うために_wsetlocale関数もあります。<br /> |
− | + | ||
+ | |||
_wsetlocale( LC_ALL, L("Japanese") );<br /> | _wsetlocale( LC_ALL, L("Japanese") );<br /> | ||
− | とします。こちらはwchar.hをインクルードするだけで使えるとのこと。 | + | |
+ | |||
+ | とします。こちらはwchar.hをインクルードするだけで使えるとのこと。 | ||
wcslenは文字列の文字数をカウントする関数です。通常のマルチバイト文字でもワイド文字でもない、何もしない関数はstrlen関数になります。<br /> | wcslenは文字列の文字数をカウントする関数です。通常のマルチバイト文字でもワイド文字でもない、何もしない関数はstrlen関数になります。<br /> | ||
− | + | ||
− | + | ||
− | さらにwcher_t型を使うには、プリプロセッサでwchar.hを読み込まなくてはならず、 | + | |
+ | さらにwcher_t型を使うには、プリプロセッサでwchar.hを読み込まなくてはならず、 | ||
+ | |||
+ | |||
<nowiki>#include<wchar.h></nowiki>と記述しないといけないです。<br /> | <nowiki>#include<wchar.h></nowiki>と記述しないといけないです。<br /> | ||
従って、ワイド文字列版のプログラムは以下のようになります。 | 従って、ワイド文字列版のプログラムは以下のようになります。 | ||
+ | |||
+ | |||
<syntaxhighlight lang="cpp" line start="1"> | <syntaxhighlight lang="cpp" line start="1"> | ||
#include <iostream> | #include <iostream> | ||
73行: | 81行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br /> | <br /> | ||
− | + | TCHAR型も同じようなものですが、プロジェクトの設定次第で置き換わるということが特徴です。これでプロジェクトの設定をUnicodeの文字セットにしていれば、wchar_t型になり、さらにTCHAR型を使うには、プリプロセッサでtchar.hを読み込まなくてはならず、<br /> | |
− | + | ||
− | + | <nowiki>#include<tchar.h></nowiki> | |
− | <nowiki>#include<tchar.h></nowiki | + | |
− | + | と記述しないといけないです。setlocale関数も_tsetlocale関数として置き換えておくことができます。Unicodeセットのプロジェクト設定なら結局_wsetlocaleに置き換わるだけです。文字列リテラルは_T(" ")といった形式で記述しておきます。_tcslen関数はwcslen関数と同じです。このようにマルチバイト文字列版、ワイド文字列版、プロジェクト設定に従うTCHAR版の3つの関数があります。cout関数にはTCHAR版が無いようなので、最初からstd::wcoutと記述するか、wcout関数と_tcout関数が同じになるように定義する必要があります。実用的にはあまり使わない関数なので、あってもなくても困りません。<br /> | |
− | + | ||
− | + | ||
− | + | C++標準関数の文字列操作系の関数を使わないようにするのが、自分は良いと思います。自分のパソコンの環境だけで、ちょっとしたことのために、マクロ定義するような手法は嫌いです。何をやってるのかが分からなくなっていきやすいような気がします。長い置き換えが必要な部分だけをプログラムにするようにしています。<br /> | |
− | + | ||
− | + | ||
− | + | ||
− | C++ | + | |
− | + | ||
− | + | ||
<br /> | <br /> | ||
従って、TCHAR版のプログラムは以下のようになります。<br /> | 従って、TCHAR版のプログラムは以下のようになります。<br /> | ||
104行: | 106行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
となります。 | となります。 | ||
− | TCHAR型のユニコード(UTF-16) | + | TCHAR型のユニコード(UTF-16)設定にした場合、wchar_t型のcStr0は配列番号0~21の22の大きさを持つ配列になります。Unicode文字セットですのでShft_JISとは異なる数値が使われますが、0番から順に<br /> |
− | + | ||
0x8868(表),0x793A(示),0xFF1A(:),0x3088(よ),0x306D(ね),0x30A6(ウ),0x30A3(ィ),0x30AD(キ),0x306E(の),0x6A5F(機),0x80FD(能)<br /> | 0x8868(表),0x793A(示),0xFF1A(:),0x3088(よ),0x306D(ね),0x30A6(ウ),0x30A3(ィ),0x30AD(キ),0x306E(の),0x6A5F(機),0x80FD(能)<br /> | ||
0x003C(<nowiki><</nowiki>),0x0079(y),0x006F(o),0x006E(n),0x0065(e),0x0077(w),0x0069(i),0x006B(k),0x0069(i),0x003E(<nowiki>></nowiki>),0x0000(\0)<br /> | 0x003C(<nowiki><</nowiki>),0x0079(y),0x006F(o),0x006E(n),0x0065(e),0x0077(w),0x0069(i),0x006B(k),0x0069(i),0x003E(<nowiki>></nowiki>),0x0000(\0)<br /> | ||
− | + | ||
− | + | のように格納されています。あんまり変わり映えしませんが、プロジェクトの設定に従うという意味ではTCHAR型を使うのが少しお勧めです。気を付けなければならないのは、Shift_JIS(CP932)コード文字セットで格納された配列をユニコード文字セットのプロジェクトで受け取ったり、その逆のことが起こったりする場合には変換が必要になったりと、いいことばかりではありません。この他、文字コードにはShift_JIS(CP932)ではないShift_JISやEUCやMac日本語といった文字コードもあり、可能性だけで考えると | |
− | + | ||
− | + | ||
− | + | ||
Unicode:UTF-8/UTF-16/UTF-32<br /> | Unicode:UTF-8/UTF-16/UTF-32<br /> | ||
Shift_JIS:CP932/shift_jis/shift_jis2000/shift_jis2004<br /> | Shift_JIS:CP932/shift_jis/shift_jis2000/shift_jis2004<br /> | ||
119行: | 120行: | ||
JIS:CP50220/ISO-2022-JP/ISO-2022-JP-1/ISO-2022-JP-2004/ISO-2022-JP-3<br /> | JIS:CP50220/ISO-2022-JP/ISO-2022-JP-1/ISO-2022-JP-2004/ISO-2022-JP-3<br /> | ||
JIS 1Byte:ISO-2022-JP/CP50221<br /> | JIS 1Byte:ISO-2022-JP/CP50221<br /> | ||
− | + | ||
− | + | ||
− | + | といった文字コードが存在し、外国語文字コードセットも含めるとかなりの数の文字コードが世界に広がっています。Unicodeも扱いがいくつかあるため、実はもう少し勉強しないといけないです。VisualStudioでUnicodeと選択した場合は、UTF-16で扱われているということになります。UTF-8では英数字が1Byte、日本語は3Byteを使います。テキストエディタは、このあたりの解釈が厳密で、ファイルを保存するときにも文字コードセットと符号化方式を遵守していますし、互換性を高めているものが、多いです。複雑過ぎて、自分には作れそうもないですね。<br /> | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
WindowsのVisualStudioなどでWin32 APIを使える環境であれば、以下のような型もあります。<br /> | WindowsのVisualStudioなどでWin32 APIを使える環境であれば、以下のような型もあります。<br /> | ||
LPCSTR =const CHAR * <br /> | LPCSTR =const CHAR * <br /> | ||
142行: | 142行: | ||
であり、その略の型名が対応しているとのこと。<br /> | であり、その略の型名が対応しているとのこと。<br /> | ||
PCSTR/PCWSTR/PCTSTR/PSTR/PWSTR/PTSTRと先頭にLが着かないものはWin16時代に使われたものですが、今では差がありません。<br /> | PCSTR/PCWSTR/PCTSTR/PSTR/PWSTR/PTSTRと先頭にLが着かないものはWin16時代に使われたものですが、今では差がありません。<br /> | ||
− | + | ||
− | MFC(MicrosoftFaundationClass) | + | |
− | + | MFC(MicrosoftFaundationClass)というMicrosoftが提供しているクラスの文字列型には文字列の操作を強化したCStringもあります。有名なので手ごわいですが、これはMFCです。MFCは無料では配られていないクラスライブラリでして、Microsoftが定義した型ってのはすごく一般的にも使われるくらい流行します。ということで、使うべき型は、WIN32 APIでもLPCTSTR/PCTSTRあるいはLPTSTR/PTSTRということになりましょうか。とはいっても、世界中にはいろんな型の文字列で操作されますので、いろいろな変換が必要になります。<br /> | |
− | + | ||
− | + | ||
− | + | ここではwchar_t型で文字列を使うために、TCHAR型を使い、ワイド文字列用の各関数wcsで始まるような関数を使います。マルチバイト文字列とした場合はchar型でマルチバイト文字列用の各関数_wbやwbで始まるような関数に置き換えられることを意味します。ってことはstrcpyという文字列コピー関数や、strcat(文字列連結)、strlen(文字列カウント)のようなstrで始まるようなC標準ライブラリ関数は使われないことになります | |
− | + | ||
− | + | ||
− | + | 最近は文字列操作関数にxxx_sやxxx_lのようなセキュア思想(本当に安全なのかどうかは不明?使い方よっては間違いだらけのプログラムになる可能性もある)の文字列操作関数がありまして、大雑把に分類すると文字列操作の関数は上記のようなことから、以下のような文字列操作関数に分類できます。<br /> | |
− | + | ||
− | + | ||
− | + | ||
− | 最近は文字列操作関数にxxx_sやxxx_lのようなセキュア思想(本当に安全なのかどうかは不明?使い方よっては間違いだらけのプログラムになる可能性もある) | + | |
− | + | ||
*strxxx系関数<br /> | *strxxx系関数<br /> | ||
*マルチバイト文字_mbxxxx関数/mbxxxx関数<br /> | *マルチバイト文字_mbxxxx関数/mbxxxx関数<br /> | ||
173行: | 168行: | ||
LPCSTR/LPCWSTR/LPCTSTR/LPSTR/LPWSTR/LPTSTR/PCSTR/PCWSTR/PCTSTR/PSTR/PWSTR/PTSTR/<br /> | LPCSTR/LPCWSTR/LPCTSTR/LPSTR/LPWSTR/LPTSTR/PCSTR/PCWSTR/PCTSTR/PSTR/PWSTR/PTSTR/<br /> | ||
という型…<br /> | という型…<br /> | ||
− | + | ||
− | + | ||
− | + | どれか一つに決めて使うのは自分次第ですが、世界中のプログラマがどれを使うかは、わかりません。しかもどの関数も微妙に動作が違ったりするので、完全な理解をしようとすると、途方に暮れそうになります。でも、まぁそれだけの種類があるんだなぁとわかってさえいれば、その都度、変換方法を調べるということができるので、それでいいのかなぁと思ったりもします。で、文字コードセット変換…リトルエンディアン…ビッグエンディアン…文字コードセットの符号化方式UTF-8/UTF-16/UTF-32その他…もうね。なんか崩壊してるような気もするけど、やるしかないわなorz<br /> | |
− | + | ||
− | + | ||
− | + | 学校で教えてくれるプログラミングがいかにその一部分だけを勉強していたのかを思い知らされる現実。そして、これを覚えたところでWindowsプログラミングができるわけでもないという、目指すべき頂上の遠さ。全部を理解しようなんて思わないことですね。必要最低限の装備でどこまで登れるか?登山はあんまりやったことがないのでアレなんすけど<br /> | |
− | + | ||
− | + | ||
− | + | そんな軽装備で山登りなんて始めたら、間違いなく死ににいくようなもんです。それでも目指すべきところがあるのならば、頑張るしかないっすね。自分自身はMFCを使ったアプリも複雑過ぎて理解しきれなかったし、ある程度は理解しようとしたんですけど…。C++を理解して、MFCのちょいかじり、さらにその先にあるC++/CLI、DirectShowを使ってみたりもしましたが、いやはや。どこまで理解できたのやら(汗。Win32APIだけでUSBラジオを操作したり、音を出力する質素なアプリとか、そういうのを作るのが精一杯でしたね。あと面白いのはSteinBerg社の提供しているVSTiスケルトンから音楽やMIDI処理系のDLL開発をするのも楽しかったような。 | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
自分もわからなかったことを、もう一度、理解してみようと思います。<br /> | 自分もわからなかったことを、もう一度、理解してみようと思います。<br /> | ||
== '''マルチバイト文字列、ワイド文字列の相互変換''' == | == '''マルチバイト文字列、ワイド文字列の相互変換''' == | ||
まずは、文字列の配列で以下のように格納されているものがあって、<br /> | まずは、文字列の配列で以下のように格納されているものがあって、<br /> | ||
+ | |||
TCHAR *cStr0[]={_T("表示:よねウィキの機能<yonewiki>"),_T("表示:よねウィキの機能1<yonewiki>"),_T("表示:よねウィキの機能2<yonewiki>")};<br /> | TCHAR *cStr0[]={_T("表示:よねウィキの機能<yonewiki>"),_T("表示:よねウィキの機能1<yonewiki>"),_T("表示:よねウィキの機能2<yonewiki>")};<br /> | ||
− | + | ||
− | + | ||
+ | を単純にpcStr0というポインタ変数を使って、まるまるコピーする場合はこんな風に自分ならやります。動的にメモリを確保してもらいますが、それで効率が本当にいいのか悪いのかは知りません。なんとなくやりきった感じだけはします。<br /> | ||
<syntaxhighlight lang="cpp" line start="1"> | <syntaxhighlight lang="cpp" line start="1"> | ||
#include <iostream> | #include <iostream> | ||
220行: | 211行: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | 本当は12行目のコピーをする関数である_tcscpy_s関数は語尾の_sの無い関数を使いたいところですが、warningが表示されるので、あえて使いこなします。_tcscpy_sの第一引数はコピー先のTCHAR型先頭アドレスでコピーするのに必要な配列の大きさを持っていれば良いです。第二引数では、コピー先の配列の大きさを指定しています。第三引数はコピー元のTCHAR型の先頭アドレスです。<br /> | |
− | + | ||
− | + | ||
− | + | ||
− | + | 7行目のNew演算子では、TCHAR型のポインタのポインタ型の配列大きさを3を確保して、実体化しています。アドレスを保持できる4Byteの大きさの領域が配列番号0~3まで作られたことになります。10行目のNew演算子では、cStr[0]~[2]の文字列の文字数+1の大きさの配列をTCHAR型で確保します。ワイド文字列のwchar_t型でも21文字+1、22文字+1、22文字+1と順番に確保しますし、マルチバイト文字ならchar型ですので、すべて全角文字に対しては2byte、2文字分の領域が必要だと計算し、32文字+1、33文字+1、33文字+1を確保します。何故+1文字分を確保するかと言えば、文字列の最後には\0を格納してくれるので、その分をあけておかなければなりません。<br /> | |
− | + | ||
− | + | ||
− | + | 18行目、20行目では、delete演算子で動的生成した領域の放棄を宣言して、リソースを返却します。使い終わったら速やかに、返す。<br /> | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
出力結果はマルチバイト文字設定だと<br /> | 出力結果はマルチバイト文字設定だと<br /> | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
280行: | 266行: | ||
cStr0=表示:よねウィキの機能2<yonewiki> | cStr0=表示:よねウィキの機能2<yonewiki> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | となります。Visual C++ | + | となります。Visual C++をつかわれているのであれば、プロジェクトの設定をマルチバイトにしたり、Unicodeにしてみたりして下さい。TCHAR型で記述しているので、どちらでも動作すると思います。<br /> |
− | + | ||
− | + | ||
− | + | それで、なんでしたっけ、ワイド文字列とマルチバイト文字列の相互互換なんですけど、ようするにこのコピーをするときにワイド文字列とマルチバイトが混じっているケースで考えて、どのように対処すればいいのかで、 | |
− | + | 説明ができると思ったのでした。mbstowcs関数とwcstombs関数でやりとりが出来るようになっています。実際、こんなケースがあるのかは知りませんが、こんな関数があるってことは、テキストをどこからか読み込んだ場合とか、そういったプログラムから引数として受け取るとか、そういったケースもあるのでしょう。関数の引数はそれぞれ異なるので、気を付けなければなりません。<br /> | |
− | + | ||
− | + | ||
− | + | で、無理矢理にそういったサンプルのプログラムを作るのは意外と面倒でして、サンプルは鋭意執筆中ということにしておきたいと思います。ぉぃ。っていうか、MSDNライブラリが落っこちてるみたいで、厳密な解釈を調べながら書くことができない。mbstowcs関数にも_tbstowcsとかmbstowcs_sとかmbstowcs_s_lとかあると思うんですけど、その辺りを知ることが出来ない。その逆もしかり。<br /> | |
− | + | ||
− | + | ||
− | <br /> | + | ようはchar型に収められた文字列をwchar_t型に変換したり、wchar_t型で収められた文字列をchar型に変換したりするってことなんですけど。UnicodeとShift_JISの変換もここで知っておくべきか…。つうか、この記事、長すぎっ。誰も理解できないんじゃね?って思う今日この頃。<br /> |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
とかいいつつ、サンプルプログラムを作りました。<br /> | とかいいつつ、サンプルプログラムを作りました。<br /> | ||
mbstowcs関数とwcstombs関数はやはり、mbstowcs_s関数とwcstombs_s関数があって更には、<br /> | mbstowcs関数とwcstombs関数はやはり、mbstowcs_s関数とwcstombs_s関数があって更には、<br /> | ||
386行: | 366行: | ||
の処理を記述しました。<br /> | の処理を記述しました。<br /> | ||
mbstowcs_s(sizeReturnValue, NULL, 0,cStr1[i], 0);<br /> | mbstowcs_s(sizeReturnValue, NULL, 0,cStr1[i], 0);<br /> | ||
− | + | のように第二引数には本来、変換後の文字列の先頭アドレスを記述しますが、NULLと指定して、第三引数の変換後の配列要素数も0にして、第四引数に変換元の文字列の先頭アドレスを記述し、変換する要素数も0を指定するとsize_t型のポインタ変数sizeReturnValueに変換に必要な配列サイズが返ってきます。その返却された値を | |
− | + | ||
− | + | ||
− | + | requiredSize = *sizeReturnValue;のようにしてコピーしておいて、 | |
− | requiredSize = *sizeReturnValue;のようにしてコピーしておいて、 | + | |
+ | |||
mbstowcs_s(sizeReturnValue, pcStr2[i], requiredSize, cStr1[i], requiredSize);<br /> | mbstowcs_s(sizeReturnValue, pcStr2[i], requiredSize, cStr1[i], requiredSize);<br /> | ||
+ | |||
+ | |||
とすることで変換がされます。<br /> | とすることで変換がされます。<br /> | ||
逆のwcstombs_sも同様です。やったことないようなプログラムでしたので、たまには、こうして確かめてみるのも良いですね。<br /> | 逆のwcstombs_sも同様です。やったことないようなプログラムでしたので、たまには、こうして確かめてみるのも良いですね。<br /> | ||
<br /> | <br /> | ||
− | + | ちょっと出力結果に冗長さを設定したサンプルプログラムなので、以下のように出力が長くなりましたが、全部貼っておきます。<br /> | |
− | + | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
マルチバイト文字→ワイド文字変換 | マルチバイト文字→ワイド文字変換 |