C 文字列操作のソースを表示
新しいページはコチラ
移動:
案内
,
検索
※このページではC言語にも存在していたという意味で記事タイトルがC 文字列操作になっていますが、<br /> [[C PlusPlus|C++]]でも同様です。[[C PlusPlus|C++]]だけの機能がある場合は明記します。<br /> <br /> == '''文字列操作''' == 文字列のコピー、連結、比較、一致、区切り文字分割、探索、文字列長取得といった操作を文字列操作と呼びます。上記のような操作はCRT関数として提供されているため、関数の使い方さえ覚えれば簡単に操作できます。 更に、文字列の型変換、文字コード変換、大文字小文字変換、半角文字、全角文字変換、ファイルパス操作、ファイル名操作、拡張子取得といった文字列操作の応用もプログラミングでは必要になってきますし、文字列の検索と置換、ファイルへの入出力といった操作までを習得すると概ねの操作ができるようになります。<br /> 上記のように日本語でまとめて言い換えるのは簡単ですが、一つ一つを実際にやってみるとなると、そう簡単でもありません。メモリに保管される文字列を操作するというのは、手続きが複雑です。コピーひとつにしても、どういった文字列を基にして、何文字目から何文字目までをコピーするのか?それにはどれくらいの大きさの文字列長があるのか?どういった変数に格納するのか?領域はちゃんと確保されているのか?手続きがうまくいかなかった場合はどうするのか?と何気に細かいことを教えてあげないと動かないのがコンピュータです。コンピュータ側からすると、人間のようには解釈は出来ない、そのかわりわからないことがあれば、どんな地道なことをしててでも調べてやるから、コンピュータに指令するのに必要な情報をそろえてほしい。<br /> まとめては動作させれないけど、内部的にはひとつづつ着実にコピーして、最終的には全部をコピーしてくれる。なんだか新入社員のようにいちいち指示しないといけないけど、まぁ的確に指示をすればやる気だけはあって、こなしてくれる。新入社員はほっといても成長しますが、コンピュータはほっとくと延々と成長しません。新入社員さんでも、あまりに放置すると教育不足ということで、指導者の責任問題とか、新人さんの人生を曲げてしまうという強烈な負のスパイラルが発生します。人間にはコンピュータにはまだまだ備えることのできない心って奴があります。大事にしないとね。ともかく、コンピュータが勝手にやってくれるようになるには、勝手にやれるようになるための成長するプログラムが必要になります。偉い人たちは地道にやっているようです。<br /> 成長云々の件はここでは関係ありませんので、置いておくとして、文字列の操作をひとつづつやってみましょう。(書きかけの記事です。最終更新131128)<br /> 文字列操作に関する関数は以下のアドレスのとおりです。<br /> http://msdn.microsoft.com/ja-jp/library/f0151s4x.aspx<br /> 上記があれば、自分が説明する必要はもうないかなと思うわけですが、一応、自分なりに。<br /> =='''文字列長取得'''== 文字列の長さを知りたいと思うことは、日常ではほとんどないですが、プログラムでは必要になるパターンが多いです。例えば、どれくらいのメモリサイズを確保すれば、いいのか?とか、文字列から抜き出した文字数が長い場合にはスクロールバーをつけたりとか、文字列の長さによって処理を分岐させたりすることもあります。この他、C言語においては、ほとんどの文字列操作関数で、その操作する文字列変数の文字列の長さを引数として与えなければならなかったりと、文字列操作の中でも基本中の基本となる部分です。知能指数の低い自分は文字数の足し算、引き算で間違えたりすることも多いです。うまく数えないと、枠にぴったりはまらないのがプログラム。<br /> リファレンスは以下のとおりです。<br /> http://msdn.microsoft.com/ja-jp/library/78zh94ax.aspx<br /> http://msdn.microsoft.com/ja-jp/library/z50ty2zh.aspx<br /> _tcslen(TCHA型設定時)/wcslen(Unicode設定)/strlen(マルチバイト設定)マルチバイト設定時の日本語対応関数 _mbslenになります。第一引数がNULLのとき、アクセス違反が発生します。<br /> lenの前にnが付くものは第二引数に最大文字数を設定する必要があり、文字列がそれを超えた場合は最大文字数を返します。<br /> _tcsnlen(TCHA型設定時)/wcsnlen(Unicode設定)/strnlen(マルチバイト設定) サフィックスに_sが付く関数では、第一引数がNULLときは戻り値が0になります。<br /> マルチバイト設定時の日本語対応関数 _mbsnlen<br /> <br /> _mbstrlenおよび_mbstrnlen は無効なマルチバイトを含む場合に戻り値-1を返します。_mbstrnlen は最大文字を超えると例外処理が発生し戻り値に-1とするとともにEINVAL に errnoを格納します。<br /> 更にサフィックスに_lが付くものは最後の引数として、ロケール設定ができます。ロケール設定の無い関数はsetlocale関数で設定された値に従います。<br /> 全部で<br /> strlen、strlen_l、wcslen、wcslen_l、_mbslen、_mbslen_l、_mbstrlen、_mbstrlen_l , strnlen、strnlen_s、strnlen_l、wcsnlen、wcsnlen_s、wcsnlen_l、_mbsnlen、_mbsnlen_l、_mbstrnlen、_mbstrnlen_l <br /> これだけの種類があります。<br /> 要するに?<br /> _tcslenを使うのが良いでしょう。Locale設定はあらかじめ実施しておくのが良いと思います。strnlen_sやwcsnlen_sはNULLの文字列の場合に0を返してくれるのはなんか良さげですが、文字列の終端が必ず\0で終わっていさえすれば必要のないことです。それはヌル文字でもいいわけです。アドレスがヌルのヌルポインターのときにプログラムが止まるよって言ってます。なんか、いっぱいありすぎて迷うけど…。 _tcslen!<br /> _lが付く関数は個別にLocale変換が必要な場合にのみ使えば良いでしょう。_tcsnlenで最大文字数を設定するのは、一見安全そうですが、なんか無駄なような気がします。あきらかに最大文字数がわかるような場合には、なんか入れておいて_tcsnlen_sってのはいい選択肢だと思います。<br /> <syntaxhighlight lang="cpp" line start="1"> #include <tchar.h> int main() { _tsetlocale(LC_ALL, _T("Japanese")); const TCHAR *cStr0[]={_T("表示:よねウィキの機能<yonewiki>"),_T("表示:よねウィキの機能1<yonewiki>"),_T("表示:よねウィキの機能2<yonewiki>")}; for(int i = 0; i < (sizeof(cStr0)/sizeof(*cStr0)); i++){ _tprintf(_T("%2d/%2d:cStr0[%2d]=%s\nStrCount=%d\n\n"),i, sizeof(cStr0)/sizeof(*cStr0),i, cStr0[i],_tcslen(cStr0[i])); } } </syntaxhighlight> 出力結果 <syntaxhighlight lang="cpp"> 0/ 3:cStr0[ 0]=表示:よねウィキの機能<yonewiki> StrCount=21 1/ 3:cStr0[ 1]=表示:よねウィキの機能1<yonewiki> StrCount=22 2/ 3:cStr0[ 2]=表示:よねウィキの機能2<yonewiki> StrCount=22 </syntaxhighlight> _mb系の関数を利用するには、<nowiki>#include <mbstring.h></nowiki>をインクルードする必要があります。<br /> 更に_mbslenは文字列長探索をしたい文字列変数の引数が、unsigned char型ですので、wchar_t型、char型の引数では文字列長を探索することは出来ません。あえて実施するならば、reinterpret_cast<unsigned char*>(※charポインタ型※)と強制的なキャストを実施することで、動作させることができます。_mbstrlenはchar型を引数にしますので、wchar_t型を使わない場合の日本語文字列長検索として使うことが出来ます。<br /> 但し、この強制キャストは定数文字列const宣言のある文字列に対しては操作が出来ないため、文字列のコピーを作成する必要があります。文字列コピー操作の詳細は次の項目に記載予定なので、順番に読み進めている人は、コピー操作について理解してから戻ってきた方が良いかもしれません。<br /> <syntaxhighlight lang="cpp" line start="1"> #include <tchar.h> #include <mbstring.h> int main() { _tsetlocale(LC_ALL, _T("Japanese")); const char *cStr1[]={"", "表示:よねウィキの機能<yonewiki>", "表示:よねウィキの機能1<yonewiki>", "表示:よねウィキの機能2<yonewiki>"}; char **ppcStr1 = new char* [sizeof(cStr1)/sizeof(*cStr1)]; _tprintf(_T("const マルチバイト文字→マルチバイト文字コピー→_mbslen関数2バイト文字認識文字列長探索\n")); for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ ppcStr1[i] = new char[strlen(cStr1[i]) + 1];//まずは単純に文字列をコピーするための領域を確保。 strcpy_s(ppcStr1[i], strlen(cStr1[i]) + 1,cStr1[i]);//コピー } for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ //強制キャストでunsigned char*型に変換して文字列長を探索。 printf("%2d/%2d:cStr1[%2d]=%s\nStrCount=%d\n\n",i, sizeof(cStr1)/sizeof(*cStr1),i, ppcStr1[i],_mbslen(reinterpret_cast<unsigned char*>(ppcStr1[i]))); } for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ delete[] *(ppcStr1 + i); } delete[] ppcStr1; } </syntaxhighlight> という具合にして、const char→char→_mabslenで文字列長探索が出来ます。出力結果は以下のとおりです。<br /> <syntaxhighlight lang="cpp"> const マルチバイト文字→マルチバイト文字コピー→_mbslen関数2バイト文字認識文字列長探索 0/ 4:cStr1[ 0]= StrCount=0 1/ 4:cStr1[ 1]=表示:よねウィキの機能<yonewiki> StrCount=21 2/ 4:cStr1[ 2]=表示:よねウィキの機能1<yonewiki> StrCount=22 3/ 4:cStr1[ 3]=表示:よねウィキの機能2<yonewiki> StrCount=22 </syntaxhighlight> _mbstrlen関数を使う場合はコピー操作が必要にならず、const宣言している文字列変数を使っての文字列長探索ができます。<br /> <syntaxhighlight lang="cpp" line start="1"> #include <tchar.h> #include <mbstring.h> int main() { _tsetlocale(LC_ALL, _T("Japanese")); const char *cStr1[]={"", "表示:よねウィキの機能<yonewiki>", "表示:よねウィキの機能1<yonewiki>", "表示:よねウィキの機能2<yonewiki>"}; _tprintf(_T("const マルチバイト文字→_mbstrlen関数2バイト文字認識文字列長探索\n")); for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ printf("%2d/%2d:cStr1[%2d]=%s\nStrCount=%d\n\n",i, sizeof(cStr1)/sizeof(*cStr1),i, cStr1[i],_mbstrlen(cStr1[i])); } } </syntaxhighlight> 出力結果は以下のとおりです。<br /> <syntaxhighlight lang="cpp"> const マルチバイト文字→_mbstrlen関数2バイト文字認識文字列長探索 0/ 4:cStr1[ 0]= StrCount=0 1/ 4:cStr1[ 1]=表示:よねウィキの機能<yonewiki> StrCount=21 2/ 4:cStr1[ 2]=表示:よねウィキの機能1<yonewiki> StrCount=22 3/ 4:cStr1[ 3]=表示:よねウィキの機能2<yonewiki> StrCount=22 </syntaxhighlight> といった具合にいろいろな関数があるので、一つづつ掘り下げて理解しておくのも、必要です。こういう違いがあるということを把握していれば、臨機応変に対応しやすくなるかもです。自分は分かったつもりにならずに、常に謙虚に確かめてみる姿勢ってのは、必要なんじゃないかと思います。そして常に、自分が実施するであろうパターンを網羅して確かめる。だから、あえて文字列の配列の場合にどうやればいいのかを探ります。 =='''文字列コピー'''== 文字列のコピー?なんでコピーするの?ってなりそうですけど、変数の代入みたいなものです。元の文字列はとっておいて、コピーした方を加工するということです。あるいはその逆。紙のコピーだと原版が綺麗だけど、原版もコピーも同じだから…<br /> a=13;<br /> b=a;<br /> b=b*b;<br /> b=a;<br /> b=b*b*b;<br /> ってな感じのことやったりしません?aの値は取っておきたい。そういうときに使ったりするのかなぁと思います。<br /> リファレンスは以下のとおりです。<br /> http://msdn.microsoft.com/ja-jp/library/kk6xf663.aspx<br /> http://msdn.microsoft.com/ja-jp/library/td1esda9.aspx<br /> http://msdn.microsoft.com/ja-jp/library/xdsywd25.aspx<br /> http://msdn.microsoft.com/ja-jp/library/5dae5d43.aspx<br /> また、例によってマルチバイト文字版strcpy、ワイド文字版wcscpy、マルチバイト2バイト文字認識版_mbscpy、セキュリティ強化版の_sサフィックスがあります。_s無し版の引数はコピー先文字列変数先頭char型アドレス、コピー元文字列変数先頭char型アドレス(文字列の終端に\0があること)となっています。_mbscpyの引数は第一引数、第二引数共にunsigned charになっています。この微妙に使いにくい引数の異なり…。しょうがないのかなぁ。<br /> そして、_s版は第2引数にコピー先文字列変数先頭char型アドレスの大きさを必要とします。_sが付かない関数で第二引数だったコピー元は第三引数にずれます。strncpyのようにcpyの前にnが付くパターンでマルチバイト文字版、ワイド文字版、マルチ2バイト文字対応版と更には_lサフィックスでロケール個別設定ができる関数があります。マルチバイト2バイト文字対応版にはバイト長を引数とするcpyの前にbが付いたものもあります。> でも…マルチバイト2バイト文字対応文字ってもともと配列の要素一つに1バイトを格納しているから、バイト長で扱っても、要素数で扱っても変わらないから何が違うのか?よくわからない。_mbs系のcpy関数の利点ってなんだろう。このへんはまた今度、考えてみよう。 全部で、<br /> strcpy、wcscpy、_mbscpy , strcpy_s、wcscpy_s、_mbscpy_s ,<br /> strncpy、_strncpy_l、wcsncpy、_wcsncpy_l、_mbsncpy、_mbsncpy_l , strncpy_s、_strncpy_s_l、wcsncpy_s、_wcsncpy_s_l、_mbsncpy_s、_mbsncpy_s_l<br /> _mbsnbcpy、_mbsnbcpy_l , _mbsnbcpy_s、_mbsnbcpy_s_l <br /> これだけあります。<br /> で、結局は_tcsncpy_sを使いなさいってことになります。Unicode設定ならワイド文字版で、文字列長に厳しい設定が必要なwcsncpy_sだね。第二引数は配列の大きさ+終端\0のための要素1つ分。バイト数ではないです。動的に生成した変数の場合は配列の大きさが取得できないので、wcslen(_tcslen)のような文字列長取得関数を使って、戻ってきた値に\0の要素のために1を加算した値が良いです。<br /> <syntaxhighlight lang="cpp" line start="1"> #include <iostream> //#include<locale.h> tchar.hがインクルードされていれば、いらない。 #include<tchar.h> int main() { _tsetlocale( LC_ALL, _T("Japanese")); size_t requiredSize = 0; size_t sizecStr0=0; TCHAR *cStr0[]={_T("表示:よねウィキの機能<yonewiki>"),_T("表示:よねウィキの機能1<yonewiki>"),_T("表示:よねウィキの機能2<yonewiki>")}; const char *cStr1[]={" ","表示:よねウィキの機能<yonewiki>","表示:よねウィキの機能1<yonewiki>","表示:よねウィキの機能2<yonewiki>"}; TCHAR **ppcStr0 = new TCHAR*[sizeof(cStr0)/sizeof(*cStr0)]; char **ppcStr1 = new char*[sizeof(cStr1)/sizeof(*cStr1)]; unsigned char **ppucStr2; ppucStr2 = new unsigned char*[sizeof(cStr1)/sizeof(*cStr1)]; //_tcscpy_s(wcscpy_s)関数での文字列コピー for(int i = 0; i < (sizeof(cStr0)/sizeof(*cStr0)); i++){ ppcStr0[i] = new TCHAR[_tcslen(cStr0[i]) + 1]; _tcscpy_s(ppcStr0[i], _tcslen(cStr0[i]) + 1,cStr0[i]);//ココ! } //strcpy_s関数での文字列コピー for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ ppcStr1[i] = new char[strlen(cStr1[i]) + 1]; strcpy_s(ppcStr1[i], strlen(cStr1[i]) + 1,cStr1[i]);//ココ! } //_mbscpy_s関数での文字列コピー for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ sizecStr0 = strlen(ppcStr1[i]) + 1; ppucStr2[i] = new unsigned char[sizecStr0]; _mbscpy_s(ppucStr2[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]));//ココ! } //出力部分 for(int i = 0; i < sizeof(cStr0)/sizeof(*cStr0); i++){ _tprintf(_T("_tcslen(cStr0[i])=%d\nppcStr0=%s,\n cStr0=%s,\n\n"),_tcslen(cStr0[i]),*(ppcStr0 + i),*(cStr0 + i)); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ printf("strlen(cStr1[i])=%d\nppcStr1=%s,\n cStr1=%s,\n\n",strlen(cStr1[i]),*(ppcStr1 + i),*(cStr1 + i)); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ printf("_mbslen(cStr1[i])=%d\nppucStr2=%s,\n cStr1=%s,\n\n",_mbslen(ppucStr2[i]),ppucStr2[i],*(cStr1 + i)); } //動的に確保したメモリの解放処理 for(int i = 0; i < sizeof(cStr0)/sizeof(*cStr0); i++){ delete[] *(ppcStr0 + i); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ delete[] *(ppcStr1 + i); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ delete[] *(ppucStr2 + i); } delete[] ppucStr2; delete[] ppcStr0; delete[] ppcStr1; printf("\n"); return 0; } </syntaxhighlight> という感じでしたね。無理やり_mbscpy関数を使ってみるとこんな感じですね。unsigned char型は宣言と同時にnew演算子の定義は出来ないようです。const型のcharからはキャストできないから、結局は一度、strcpy_sを使って、char型の文字列に置き換えないといけないです。マルチバイト型の2バイト文字認識操作関数って結局は、char型と同じなので、文字数を数えるときはstrlenで数えないといけない。char型と_mbsxxx関数を行ったり来たりするだけです。<br /> 出力結果は以下のとおり<br /> <syntaxhighlight lang="cpp"> _tcslen(cStr0[i])=21 ppcStr0=表示:よねウィキの機能<yonewiki>, cStr0=表示:よねウィキの機能<yonewiki>, _tcslen(cStr0[i])=22 ppcStr0=表示:よねウィキの機能1<yonewiki>, cStr0=表示:よねウィキの機能1<yonewiki>, _tcslen(cStr0[i])=22 ppcStr0=表示:よねウィキの機能2<yonewiki>, cStr0=表示:よねウィキの機能2<yonewiki>, strlen(cStr1[i])=1 ppcStr1= , cStr1= , strlen(cStr1[i])=32 ppcStr1=表示:よねウィキの機能<yonewiki>, cStr1=表示:よねウィキの機能<yonewiki>, strlen(cStr1[i])=33 ppcStr1=表示:よねウィキの機能1<yonewiki>, cStr1=表示:よねウィキの機能1<yonewiki>, strlen(cStr1[i])=33 ppcStr1=表示:よねウィキの機能2<yonewiki>, cStr1=表示:よねウィキの機能2<yonewiki>, _mbslen(cStr1[i])=1 ppucStr2= , cStr1= , _mbslen(cStr1[i])=21 ppucStr2=表示:よねウィキの機能<yonewiki>, cStr1=表示:よねウィキの機能<yonewiki>, _mbslen(cStr1[i])=22 ppucStr2=表示:よねウィキの機能1<yonewiki>, cStr1=表示:よねウィキの機能1<yonewiki>, _mbslen(cStr1[i])=22 ppucStr2=表示:よねウィキの機能2<yonewiki>, cStr1=表示:よねウィキの機能2<yonewiki>, </syntaxhighlight> 上記に加えて、コピーする文字数を引数とするcpyの前にnが付く関数_tcsncpy_s/wcsncpy_s/strncpy_s/_mbsncpy_sにする場合は<br /> <syntaxhighlight lang="cpp"> … … //_tcscpy_s(ppcStr0[i], _tcslen(cStr0[i]) + 1,cStr0[i]);//ココ! _tcsncpy_s(ppcStr0[i], _tcslen(cStr0[i]) + 1,cStr0[i], _tcslen(cStr0[i]) + 1);//ココ! … … //strcpy_s(ppcStr1[i], strlen(cStr1[i]) + 1,cStr1[i]);//ココ! strncpy_s(ppcStr1[i], strlen(cStr1[i]) + 1,cStr1[i],strlen(cStr1[i]) + 1);//ココ! … … //_mbscpy_s(ppucStr2[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]));//ココ! _mbsncpy_s(ppucStr2[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]), _mbslen(reinterpret_cast<unsigned char*>(ppcStr1[i])));//ココ! … … </syntaxhighlight> と、4つの引数をとるように記述します。第4引数が出力する最大文字の配列数です。出力する文字数と考えることもできます。マルチバイト文字の場合には出力する文字数を指定できるのは効果的で、先頭から何バイト目で区切れば日本語文字が分断されないかの判断もしてくれながらの出力となります。この出力する文字数をあえてバイト単位で指定する_mbsnbcpy_sもあります。ただし、コピー先の文字列の配列はstrlenのようなバイト数分で準備する必要があることに注意が必要です。出力文字数を指定する場合は文字列全体の長さではなく、指定した文字数で必要な文字列バイト数を算出しておいて、メモリを確保するように処理を記述するのが良いかもしれません。ここでは強制キャストを使いましたが、もともとの文字列がunsigned charとして定義されているものをコピーするときに_mbs系の文字列コピーを利用するというのが自然な使い方になります。<br /> =='''文字列連結'''== 文字列の処理において、文字列を抜き出すことと、連結することはプログラミングにおいて、かなり頻繁に必要となる処理です。設定ファイルのようなものを書き出す場合に、設定1の値をAとユーザが指定した場合、文字列リテラルとして、「<設定1="」と「A」と「">」とを繋ぎ合わせて、記憶しておいて、あとで書き出し処理をしたり、あとで設定ファイルの中身を見る時に設定1の値を抜き出すためにAという値を抜き出す。そういう感じです。上記のようなXML形式の設定方法ならパースという手法によって、既に設定属性値と設定値を書き込んだり、読み込んだりするための関数が提供されていたりしますが、同じようなことを自分でやっていくということはあります。<br /> 連結は英語でcatenateと言うため、strcatのようなcatというキーワードが関数に使われます。<br /> リファレンスは以下の通りです。<br /> http://msdn.microsoft.com/ja-jp/library/tbyd7s1y.aspx<br /> http://msdn.microsoft.com/ja-jp/library/w6w3kbaf.aspx<br /> http://msdn.microsoft.com/ja-jp/library/td1esda9.aspx<br /> http://msdn.microsoft.com/ja-jp/library/d45bbxx4.aspx<br /> http://msdn.microsoft.com/ja-jp/library/5c6eeh98.aspx<br /> http://msdn.microsoft.com/ja-jp/library/h1x0y282.aspx<br /> 多い…<br /> strncat、_strncat_l、wcsncat、wcsncat_l、_mbsncat、_mbsncat_l , strncat_s、_strncat_s_l、wcsncat_s、_wcsncat_s_l、_mbsncat_s、_mbsncat_s_l <br /> strcat、wcscat、_mbscat , strcat_s、wcscat_s、_mbscat_s <br /> _mbsnbcat、_mbsnbcat_l , _mbsnbcat_s、_mbsnbcat_s_l<br /> <br /> 例によって_sのついた連結先文字列の配列サイズを明記する関数に_lのついた個別ロケール設定関数。そして連結させたい文字列の文字数を記述するncatに文字数をバイト数で指定するnbcat。あとはワイド文字のwcsで始まる関数。マルチバイトのstrで始まる関数。マルチバイト2バイト文字対応の_mbsで始まる関数。全部で22種類。引数は文字列コピーと同じですが、コピー先の変数が既に文字列が格納されてる\0で終わる文字列になっていて、処理をした結果、第一引数の文字列先頭アドレスの中身が文字列連結した結果になるという点が異なると覚えれば、連結とコピーは似ていると覚えればよいかと思います。先の文字列コピーのプログラムのコピーcpy系関数の後ろに連結cat系関数を追加して、文字列を2回繰り返されるようにしたサンプルです。所謂(いわゆる)、手抜きです。ただし、連結関数では連結後の文字列の配列大きさを要求されるため、あらかじめ動的に確保する領域が2倍になっていることに注意して下さい。<br /> <syntaxhighlight lang="cpp" line start="1"> #include <iostream> //#include<locale.h> tchar.hがインクルードされていればいらない。 #include<tchar.h> int main() { _tsetlocale( LC_ALL, _T("Japanese")); size_t requiredSize = 0; size_t sizecStr0=0; TCHAR *cStr0[]={_T("表示:よねウィキの機能<yonewiki>"),_T("表示:よねウィキの機能1<yonewiki>"),_T("表示:よねウィキの機能2<yonewiki>")}; const char *cStr1[]={" ","表示:よねウィキの機能<yonewiki>","表示:よねウィキの機能1<yonewiki>","表示:よねウィキの機能2<yonewiki>"}; TCHAR **ppcStr0 = new TCHAR*[sizeof(cStr0)/sizeof(*cStr0)]; char **ppcStr1 = new char*[sizeof(cStr1)/sizeof(*cStr1)]; unsigned char **ppucStr2; ppucStr2 = new unsigned char*[sizeof(cStr1)/sizeof(*cStr1)]; //_tcscpy_s(wcscpy_s)関数での文字列コピー for(int i = 0; i < (sizeof(cStr0)/sizeof(*cStr0)); i++){ ppcStr0[i] = new TCHAR[(_tcslen(cStr0[i]) * 2) + 1]; _tcsncpy_s(ppcStr0[i], _tcslen(cStr0[i]) + 1,cStr0[i], _tcslen(cStr0[i]) + 1);//ココ! _tcsncat_s(ppcStr0[i], (_tcslen(cStr0[i]) * 2) + 1,cStr0[i], _tcslen(cStr0[i]) + 1);//ココ! } //strcpy_s関数での文字列コピー for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ ppcStr1[i] = new char[(strlen(cStr1[i]) * 2) + 1]; strncpy_s(ppcStr1[i], strlen(cStr1[i]) + 1,cStr1[i],strlen(cStr1[i]) + 1);//ココ! strncat_s(ppcStr1[i], (strlen(cStr1[i]) * 2) + 1,cStr1[i],strlen(cStr1[i]) + 1);//ココ! } //_mbscpy_s関数での文字列コピー strcat関数部分ですでに2回繰り返しになった文字をさらに繰り返し連結する処理になってます。4回繰り返し文字列になります。 for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ sizecStr0 = (strlen(ppcStr1[i]) * 2) + 1; ppucStr2[i] = new unsigned char[sizecStr0]; _mbsncpy_s(ppucStr2[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]), _mbslen(reinterpret_cast<unsigned char*>(ppcStr1[i])));//ココ! _mbsncat_s(ppucStr2[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]), _mbslen(reinterpret_cast<unsigned char*>(ppcStr1[i])));//ココ! } //出力部分 for(int i = 0; i < sizeof(cStr0)/sizeof(*cStr0); i++){ _tprintf(_T("_tcslen(cStr0[i])=%d\nppcStr0=%s,\n cStr0=%s,\n\n"),_tcslen(cStr0[i]),*(ppcStr0 + i),*(cStr0 + i)); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ printf("strlen(cStr1[i])=%d\nppcStr1=%s,\n cStr1=%s,\n\n",strlen(cStr1[i]),*(ppcStr1 + i),*(cStr1 + i)); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ printf("_mbslen(cStr1[i])=%d\nppucStr2=%s,\n cStr1=%s,\n\n",_mbslen(ppucStr2[i]),ppucStr2[i],*(cStr1 + i)); } //動的に確保したメモリの解放処理 for(int i = 0; i < sizeof(cStr0)/sizeof(*cStr0); i++){ delete[] *(ppcStr0 + i); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ delete[] *(ppcStr1 + i); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ delete[] *(ppucStr2 + i); } delete[] ppucStr2; delete[] ppcStr0; delete[] ppcStr1; printf("\n"); return 0; } </syntaxhighlight> 出力結果<br /> <syntaxhighlight lang="cpp"> _tcslen(cStr0[i])=21 ppcStr0=表示:よねウィキの機能<yonewiki>表示:よねウィキの機能<yonewiki>, cStr0=表示:よねウィキの機能<yonewiki>, _tcslen(cStr0[i])=22 ppcStr0=表示:よねウィキの機能1<yonewiki>表示:よねウィキの機能1<yonewiki>, cStr0=表示:よねウィキの機能1<yonewiki>, _tcslen(cStr0[i])=22 ppcStr0=表示:よねウィキの機能2<yonewiki>表示:よねウィキの機能2<yonewiki>, cStr0=表示:よねウィキの機能2<yonewiki>, strlen(cStr1[i])=1 ppcStr1= , cStr1= , strlen(cStr1[i])=32 ppcStr1=表示:よねウィキの機能<yonewiki>表示:よねウィキの機能<yonewiki>, cStr1=表示:よねウィキの機能<yonewiki>, strlen(cStr1[i])=33 ppcStr1=表示:よねウィキの機能1<yonewiki>表示:よねウィキの機能1<yonewiki>, cStr1=表示:よねウィキの機能1<yonewiki>, strlen(cStr1[i])=33 ppcStr1=表示:よねウィキの機能2<yonewiki>表示:よねウィキの機能2<yonewiki>, cStr1=表示:よねウィキの機能2<yonewiki>, _mbslen(cStr1[i])=4 ppucStr2= , cStr1= , _mbslen(cStr1[i])=84 ppucStr2=表示:よねウィキの機能<yonewiki>表示:よねウィキの機能<yonewiki>表示:よねウィキの機能<yonewiki>表示:よねウィキの機能<yonewiki>, cStr1=表示:よねウィキの機能<yonewiki>, _mbslen(cStr1[i])=88 ppucStr2=表示:よねウィキの機能1<yonewiki>表示:よねウィキの機能1<yonewiki>表示:よねウィキの機能1<yonewiki>表示:よねウィキの機能1<yonewiki>, cStr1=表示:よねウィキの機能1<yonewiki>, _mbslen(cStr1[i])=88 ppucStr2=表示:よねウィキの機能2<yonewiki>表示:よねウィキの機能2<yonewiki>表示:よねウィキの機能2<yonewiki>表示:よねウィキの機能2<yonewiki>, cStr1=表示:よねウィキの機能2<yonewiki>, </syntaxhighlight> =='''文字列比較'''== 数値の比較は配列でないかぎりは単純な1変数同志の比較ですが、文字列は配列全体が一致しているかを確認することになります。かといって、自分で配列全体を相互に比較するようなプログラムを組むという必要はなく、標準で準備されている関数を使う事で比較できます。VB、PHP、Perlのような関数では関数を使わずに、数値と数値を1変数で比較するかのように比較ができる仕組みになっていますが、C言語では関数を使って比較する必要があります。面倒だ(´Д`;)。<br /> この厳密さも、C言語を難しく感じる一つの要素だと思います。配列をひとつづつ確認する作業なんだという意識づけを忘れないという意味では大事なようにも感じます。だから、ちょっとした変更の伴う比較でも、どうすればよいかを考えることができるのだと思います。VBやPHP、Perlのような便利な比較ばかりをやっているとふと、大文字小文字区別なし変換をしたいとか、半角全角区別なし変換をしたいときに、思考が止まってしまう。 そういうときにはPHPやPerl、VBでも一生懸命調べて、C言語の考え方にたどり着いて、比較することになるんでしょうけど…さいしょから、文字列比較とは、こういうものだと知っておけば、それでいいのですから、ネガティブに考えず、これを覚えれば、潰しが効くとポジティブにとらえてやっていきましょう。比較は英語でcompairと表現するため、関数名にはcmpが使われます。半導体製造工程のcmpとは違います。Chemical Micro Polisherだっけ?違った。Chemical Mechanical Polishingだった。<br /> 例によって比較の関数もマルチバイト文字、ワイド文字、マルチバイト2バイト文字対応といろいろな関数があります。<br /> strncmp、wcsncmp、_mbsncmp、_mbsncmp_l<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/eywx8zcx.aspx<br /> _strnicmp、_wcsnicmp、_mbsnicmp、_strnicmp_l、_wcsnicmp_l、_mbsnicmp_l<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/chd90w8e.aspx<br /> _stricmp、_wcsicmp、_mbsicmp、_stricmp_l、_wcsicmp_l、_mbsicmp_l<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/k59z8dwe.aspx<br /> strcmp、wcscmp、_mbscmp<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/e0z9k731.aspx<br /> _mbsnbicmp、_mbsnbicmp_l <br /> http://msdn.microsoft.com/ja-jp/library/vstudio/dyhkb6c5.aspx<br /> _mbsnbcmp、_mbsnbcmp_l <br /> http://msdn.microsoft.com/ja-jp/library/vstudio/hce588f2.aspx<br /> strcoll、wcscoll、_mbscoll、_strcoll_l、_wcscoll_l、_mbscoll_l , _stricoll、_wcsicoll、_mbsicoll、_stricoll_l、_wcsicoll_l、_mbsicoll_l, _strncoll、_wcsncoll、_mbsncoll、_strncoll_l、_wcsncoll_l、_mbsncoll_l, _strnicoll、_wcsnicoll、_mbsnicoll、_strnicoll_l、_wcsnicoll_l、_mbsnicoll_l<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/a7cwbx4t.aspx<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/2w46a1da.aspx<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/72c43s4t.aspx<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/a697c234.aspx<br /> <br /> 多い!更に多い。<br /> けどicmpってついてるやつは、大文字小文字を区別しないと考えればいいし、cmpで終わらない、collはコードページという特殊な考え方が使われること、ncpmは比較する文字数指定あり、_lはロケール個別指定、と考えればかなりすっきり。collによる比較はあとで考えましょう。<br /> <syntaxhighlight lang="cpp" line start="1"> #include <iostream> //#include<locale.h> wchar.hがインクルードされていれば、いらない。 #include<wchar.h> int main() { _wsetlocale( LC_ALL, L("Japanese")); size_t sizecStr0=0; long iCmpResult =0; TCHAR *cStr0[]={_T("表示:よねウィキの機能0<yonewiki>"),_T("表示Nよねウィキの機能12<yonewiki>"),_T("表示:よねウィキの機能2<yonewiki>")}; const char *cStr1[]={" ","表示:よねウィキの機能<yonewiki>","表示:よねウィキの機能1<yonewiki>","表示:よねウィキの機能2<yonewiki>"}; TCHAR **ppcStr0 = new TCHAR*[sizeof(cStr0)/sizeof(*cStr0)]; char **ppcStr1 = new char*[sizeof(cStr1)/sizeof(*cStr1)]; unsigned char **ppucStr2; ppucStr2 = new unsigned char*[sizeof(cStr1)/sizeof(*cStr1)]; TCHAR **ppcStr10 = new TCHAR*[sizeof(cStr0)/sizeof(*cStr0)]; char **ppcStr11 = new char*[sizeof(cStr1)/sizeof(*cStr1)]; unsigned char **ppucStr20; ppucStr20 = new unsigned char*[sizeof(cStr1)/sizeof(*cStr1)]; for(int i = 0; i < (sizeof(cStr0)/sizeof(*cStr0)); i++){ ppcStr0[i] = new TCHAR[(_tcslen(cStr0[i]) * 2) + 1]; ppcStr10[i] = new TCHAR[(_tcslen(cStr0[i]) * 2) + 1]; _tcsncpy_s(ppcStr0[i], _tcslen(cStr0[i]) + 1,cStr0[i], _tcslen(cStr0[i]) + 1);//ココ! _tcsncpy_s(ppcStr10[i], _tcslen(cStr0[i]) + 1,cStr0[i], _tcslen(cStr0[i]) + 1);//ココ! _tcsncat_s(ppcStr0[i], (_tcslen(cStr0[i]) * 2) + 1,cStr0[i], _tcslen(cStr0[i]) + 1);//ココ! } //strcpy_s関数での文字列コピー for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ ppcStr1[i] = new char[(strlen(cStr1[i]) * 2) + 1]; ppcStr11[i] = new char[(strlen(cStr1[i]) * 2) + 1]; strncpy_s(ppcStr1[i], strlen(cStr1[i]) + 1,cStr1[i],strlen(cStr1[i]) + 1);//ココ! strncpy_s(ppcStr11[i], strlen(cStr1[i]) + 1,cStr1[i],strlen(cStr1[i]) + 1);//ココ! } //_mbscpy_s関数での文字列コピー for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ sizecStr0 = (strlen(ppcStr1[i]) * 2) + 1; ppucStr2[i] = new unsigned char[sizecStr0]; ppucStr20[i] = new unsigned char[sizecStr0]; _mbsncpy_s(ppucStr2[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]), _mbslen(reinterpret_cast<unsigned char*>(ppcStr1[i])));//ココ! _mbsncpy_s(ppucStr20[i], sizecStr0,reinterpret_cast<unsigned char*>(ppcStr1[i]), _mbslen(reinterpret_cast<unsigned char*>(ppcStr1[i])));//ココ! } //出力部分 for(int i = 0; i < sizeof(cStr0)/sizeof(*cStr0); i++){ _tprintf(_T("_tcslen(cStr0[i])=%d\nppcStr0=%s,\n cStr0=%s,\n"),_tcslen(cStr0[i]),*(ppcStr0 + i),*(cStr0 + i)); for(int k = 0; k < sizeof(cStr0)/sizeof(*cStr0); k++){ iCmpResult = _tcsncmp(*(ppcStr0 + i),*(ppcStr10 + k),_tcslen(cStr0[i])); _tprintf(_T("i=%d, k=%d, iCmpResult=%ld,\n"),i,k,iCmpResult); } _tprintf(_T("\n")); } _tprintf(_T("\n")); for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ printf("strlen(cStr1[i])=%d\nppcStr1=%s,\n cStr1=%s,\n\n",strlen(cStr1[i]),*(ppcStr1 + i),*(cStr1 + i)); for(int k = 0; k < (sizeof(cStr1)/sizeof(*cStr1)); k++){ iCmpResult = strncmp(*(ppcStr1 + i),*(ppcStr11 + k),strlen(cStr1[i])); _tprintf(_T("i=%d, k=%d, iCmpResult=%ld,\n"),i,k,iCmpResult); } _tprintf(_T("\n")); } for(int i = 0; i < (sizeof(cStr1)/sizeof(*cStr1)); i++){ printf("_mbslen(cStr1[i])=%d\nppucStr2=%s,\n cStr1=%s,\n\n",_mbslen(ppucStr2[i]),ppucStr2[i],*(cStr1 + i)); for(int k = 0; k < (sizeof(cStr1)/sizeof(*cStr1)); k++){ iCmpResult = _mbsncmp(ppucStr2[i],ppucStr20[k],_mbslen(ppucStr2[i])); _tprintf(_T("i=%d, k=%d, iCmpResult=%ld,\n"),i,k,iCmpResult); } _tprintf(_T("\n")); } //動的に確保したメモリの解放処理 for(int i = 0; i < sizeof(cStr0)/sizeof(*cStr0); i++){ delete[] *(ppcStr0 + i); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ delete[] *(ppcStr1 + i); } for(int i = 0; i < sizeof(cStr1)/sizeof(*cStr1); i++){ delete[] *(ppucStr2 + i); } delete[] ppucStr2; delete[] ppcStr0; delete[] ppcStr1; printf("\n"); return 0; } </syntaxhighlight> 出力結果 <syntaxhighlight lang="cpp"> _tcslen(cStr0[i])=22 ppcStr0=表示:よねウィキの機能0<yonewiki>表示:よねウィキの機能0<yonewiki>, cStr0=表示:よねウィキの機能0<yonewiki>, i=0, k=0, iCmpResult=0, i=0, k=1, iCmpResult=-20, i=0, k=2, iCmpResult=-2, _tcslen(cStr0[i])=23 ppcStr0=表示Nよねウィキの機能12<yonewiki>表示Nよねウィキの機能12<yonewiki>, cStr0=表示Nよねウィキの機能12<yonewiki>, i=1, k=0, iCmpResult=20, i=1, k=1, iCmpResult=0, i=1, k=2, iCmpResult=20, _tcslen(cStr0[i])=22 ppcStr0=表示:よねウィキの機能2<yonewiki>表示:よねウィキの機能2<yonewiki>, cStr0=表示:よねウィキの機能2<yonewiki>, i=2, k=0, iCmpResult=2, i=2, k=1, iCmpResult=-20, i=2, k=2, iCmpResult=0, strlen(cStr1[i])=1 ppcStr1= , cStr1= , i=0, k=0, iCmpResult=0, i=0, k=1, iCmpResult=-1, i=0, k=2, iCmpResult=-1, i=0, k=3, iCmpResult=-1, strlen(cStr1[i])=32 ppcStr1=表示:よねウィキの機能<yonewiki>, cStr1=表示:よねウィキの機能<yonewiki>, i=1, k=0, iCmpResult=1, i=1, k=1, iCmpResult=0, i=1, k=2, iCmpResult=1, i=1, k=3, iCmpResult=1, strlen(cStr1[i])=33 ppcStr1=表示:よねウィキの機能1<yonewiki>, cStr1=表示:よねウィキの機能1<yonewiki>, i=2, k=0, iCmpResult=1, i=2, k=1, iCmpResult=-1, i=2, k=2, iCmpResult=0, i=2, k=3, iCmpResult=-1, strlen(cStr1[i])=33 ppcStr1=表示:よねウィキの機能2<yonewiki>, cStr1=表示:よねウィキの機能2<yonewiki>, i=3, k=0, iCmpResult=1, i=3, k=1, iCmpResult=-1, i=3, k=2, iCmpResult=1, i=3, k=3, iCmpResult=0, _mbslen(cStr1[i])=1 ppucStr2= , cStr1= , i=0, k=0, iCmpResult=0, i=0, k=1, iCmpResult=-1, i=0, k=2, iCmpResult=-1, i=0, k=3, iCmpResult=-1, _mbslen(cStr1[i])=21 ppucStr2=表示:よねウィキの機能<yonewiki>, cStr1=表示:よねウィキの機能<yonewiki>, i=1, k=0, iCmpResult=1, i=1, k=1, iCmpResult=0, i=1, k=2, iCmpResult=1, i=1, k=3, iCmpResult=1, _mbslen(cStr1[i])=22 ppucStr2=表示:よねウィキの機能1<yonewiki>, cStr1=表示:よねウィキの機能1<yonewiki>, i=2, k=0, iCmpResult=1, i=2, k=1, iCmpResult=-1, i=2, k=2, iCmpResult=0, i=2, k=3, iCmpResult=-1, _mbslen(cStr1[i])=22 ppucStr2=表示:よねウィキの機能2<yonewiki>, cStr1=表示:よねウィキの機能2<yonewiki>, i=3, k=0, iCmpResult=1, i=3, k=1, iCmpResult=-1, i=3, k=2, iCmpResult=1, i=3, k=3, iCmpResult=0, </syntaxhighlight> と、こんな感じです。結果を見るとわかるのですが、1,-1,0で結果が表現され、先頭から比較して、一番最初に異なる文字同志を比較したときの結果、文字コードの値が大きかったか小さかったかで、1と-1とに結果が分かれます。これを使って昇順に並べたりすることも出来ます。もちろん0が返ってきたときは、完全一致です。等しかったということになります。<br /> 少し変わっているのは、関数によっては、文字コードの差分値を返すものもあるという点です。_mbs系では文字コードの差分を返すことは無いようです。cmpの前にiが付く関数は差分を返すようです。ただし_mbsnicmpや_mbsicmpのような関数は差分は返しません。wcs系の関数は差分を返します。このことで差分が数値コードによる部分である場合は、その差は数字の差でもあり、一文字(一桁)の数学的な差を計算するのと同様の処理になったり、アルファベットによる連番と考えた場合でも、その差を計算していることにもなります。2バイト文字では差が大きな数値になりますが、符号付きint型で十分に収まる値です。今回は実験的にlongを使いましたが、無駄足でした。仕様のとおりに動作しますね。<br /> 但し、差分の件については、仕様に明記されていませんので、実際に利用する関数での動作を確かめてから使う方が良いと思います。仕様に明記されているのは0より大きい値を返すか小さい値を返すかのどちらかとなっています。正確なVisual C++に限らない言語仕様を検索してみたのですが、わかりませんでした。coll系の比較関数は現在のコードページに従いますので、locale情報を指定しない状態では、各PCのコードページに従います。コードページというのはcp932のような具体的な文字コードのことです。cpの後に続く数字で文字コードセットは分類されています。特段の理由がなければ、使うことは無いでしょう。selocale関数でも引数を指定しなければ各PCのコードページに従いますから、setlocaleで指定できない理由があるという特殊なケースになりそうです。それか、cmpという関数が嫌いでcollが良いと思うかとかですね。ひょっとしたら差分戻り値の件で動作が異なるかもしれません。あとで確認をしておきたいと思います。とてつもなく長いですが、その確認をしてみた結果が以下のものでして、<br /> <br /> [[文字列操作 文字列比較 実行結果1]]<br /> <br /> 528行目から534行目のように同じ'Y'0x79大文字と'y'0x89小文字の比較でありながらも、strcollでは1とstrcmpでは-1とでは結果が異なります。asciiコードでは小文字の方が大きな数字の文字コードが割り振られているため、strcmpのように Y と y の差は0x89 - 0x79で負の数値となり -1 となることを期待しますが、collは現在のコードページかつ辞書式順序を使うために小文字よりも大文字が後ということで1になります。辞書式順序って何だ?と思いつつあるのが131202時点の状況でして、さらに調査をすすめたものが<br /> <br /> [[文字列操作 文字列比較 実行結果2]]<br /> <br /> で、 *大小のみの判定<br /> :wcscmp<br /> :<br /> :wcsicoll/wcscoll/wcsnicoll/_wcsncoll<br /> :<br /> :strcmp/strncmp<br /> :<br /> :strcoll/stricoll/<br /> :<br /> :_mbscmp/_mbsicmp/_mbsncmp/_mbsnicmp/_mbscoll/_mbsicoll/_mbsncoll/_mbsnicoll<br /> <br /> :但し、半角スペースと-全角の比較が発生すると符号付き4byteの最大値を返す。2147483647=21億4748万4647<br /> :_strnicoll/_strncoll<br /> <br /> *差分を返す<br /> :wcsicmp/wcsnicmp/wcsncmp/<br /> <br /> :stricmp/_strnicmp<br /> <br /> という具合の動作であります。collの特徴的なのは辞書順と呼んでいる比較の概念だと思います。ASCIIコードでは大文字と小文字とでは、小文字の方が大きい文字コード番号が付与されていますが、wcs**coll系の比較をする関数では、小文字の方が値が小さいものとして判定してくれます。漢字の範囲になるとロケールで指定したcp932の文字コード順で比較してくれます。阿という文字と哀という文字はUnicode(UTF16)では阿-0x963F 哀-0x54C0 表-0x8868であり、Shift_JISのcp932では阿-0x88A2 哀-0x88A3 表-0x955Cと定義されていますから、阿<nowiki><</nowiki>哀<nowiki><</nowiki>表 のように比較をしてくれます。coll系の関数を使わない場合は 哀<nowiki><</nowiki>表<nowiki><</nowiki>阿のように比較されます。この阿や哀や表という名前のファイル名のテキストをWindowsのエクスプローラで昇順表示すると、この順番になることも確認できます。Shift_JISコード順でソートされてるんだなぁと確認が出来ると思います。Cp932の半角記号あたりの辞書順ってのは、どうなってるんでしょうね。これもまた今度しらべてみたいと思います。ファイル名に使えない文字あたりはどんな順番なんだろうか? '''★豆知識''' '''Unicodeの符号化方式UTF-16とは…''' 日本語の範囲ではUTF16は2バイト文字と考えて良いですが、Unicode全体では0x10FFFFまで利用することになっていますので、0x10000以上の値を持つ文字コードは4バイト文字になります。この0x10000以上の値になる場合は、ビット列で表現すると110110????xxxxxx 110111xxxxxxxxxxのような形式になり????の部分のには上位ビットと下位ビットを16ビットずつに分けた時に0xUUUUDDDDと表記するならば、0xUUUUは0x0001~0x0010の値となり得て、そのUUUU-1の値が????に入ります。xの部分には下位DDDDのビット列そのものが 入ったような値になります。そういう意味ではUnicodeのUTF-16という符号化方式では16bit(2byte)だったり32bit(4byte)のコードになります。 '''Unicodeの符号化方式UTF-8とは…''' UTF-8はASCIIコードの7ビット文字は1バイトで表し、それ以降の2バイト文字は3バイトで表すような符号化方式です。この方式でUnicode全体を表現するには最大6byteを使います。Unicodeの上位2Byteが0x1~0x10までの値しか使わないので6バイトで表せます。しかしながら日本語のほとんどは2byte文字で表現できるので、1文字あたり3バイトになるのはUTF16が2倍増しなのに対して、2.5倍増しとなるのがデメリットです。但し、半角英数文字が登場する比率で、そのデメリットは削減できる可能性もあります。日本語を10文字打ったら20byte、7文字打ったら、14byteだから+6文字を半角文字という具合です。7+6だったから、おおよそ半分半分の文字数がいいみたいね。それほど半角英数文字を使うのは技術情報を書く文書くらいだと思いますが…。その人の趣味によって、仕事によって、損得が変わるというものです。UTF-8はかなり広い範囲で使われています。それは英語圏の人が、日本語のような2バイト文字による被害をまったく被らないからだと思います。 ちなみに符号化方式によると2バイト文字はビット列を x0,x1,x2,x3, x4,x5,x6,x7, x8,x9,xA,xB, xC,xD,xE,xFと表現すると、 (1110),(x0,x1,x2,x3),(10,x4,x5),(x6,x7, x8,x9),(10,xA,xB),(xC,xD,xE,xF)となります。 文字の先頭に3バイトなら3つの1が付き、1バイト目を構成し、 次のバイト以降はバイト先頭に全て10をつける。おかげさまで、1バイト目の下位4bitと、3バイト目の下位4bitの16進数だけはそのままだけど、他のbitは16進表記が、変化します。読み起こすのは大変ですね。文字列の最初を見つけたら、そこから文字列に起こしていけば良いですが、新しい変換表を考えないと直感的にはUnicode文字のコード表には表現できないですね。 =='''文字列区切り文字分割'''== 文字列の中に区切りがある場合ってのは、例えば、<br /> Sweet Refrain/Perfume,雨のち晴レルヤ/ゆず,東京デスティニー/ポルノグラフィティ,熱愛発覚中/椎名林檎と中田ヤスタカ(CAPSULE),STORY OF MY LIFE/ONE DIRECTION,THE SEVEN SEAS/THE BAWDIES,手紙/ナオト・インティライミ,SLY/RIP SLYME,閃光 feat.10-FEET/東京スカパラダイスオーケストラ,風は西から/奥田民生,DIAMOND SKIN/GLAY,SO RIGHT/三代目 J Soul Brothers from EXILE TRIBE,White Winter Love。/ハジ→,APPLAUSE/LADY GAGA,ピタカゲ from「COUP D'ETAT[+ONE OF A KIND&HEARTBREAKER]」/G-DRAGON (from BIGBANG),LEMON/The Birthday,もったいないとらんど/きゃりーぱみゅぱみゅ,僕らの物語/GReeeeN,Lily/Dragon Ash,START IT AGAIN/AK-69,Very Merry Xmas/東方神起,SURVIVAL/EMINEM,ウォーリーヒーロー/KANA-BOON,あなたへ/エレファントカシマシ,キラーボール/ゲスの極み乙女。,Babies are popstars/松任谷由実,ROCK N ROLL(日本語字幕入り)/AVRIL LAVIGNE,HOT SHOT/GENERATIONS from EXILE TRIBE,守ってあげたい/JUJU,3 2 1/SHINee,Always/斉藤和義,ファンファーレがきこえる/Base Ball Bear,X'masラブストーリー。/ソナーポケット,Missing/androp,ラストバージン/RADWIMPS,エデン(lyric ver)/Aqua Timez,クルクル/e-girls,WHO'S NEXT/SiM,Time goes by/URATA NAOYA,Bi-Li-Li Emotion/Superfly,One day/TOKYO No.1 SOUL SET,粉雪/BENI,FEEVEER/MO'SOME TONEBENDER,No.525300887039/supercell,Hello\,999/N'夙川BOYS,Every Hero/kaho,黒猫?Adult Black Cat?/Acid Black Cherry,指でキスしよう/東京カランコロン,m@u/後藤まりこ,海と花束/きのこ帝国<br /> のようなヒットチャートベスト50があったとしたら , カンマでチャートが区切られていて、 / スラッシュで曲名とアーチスト名が区切られていることになります。<br /> こういった区切り文字毎に見ると意味が発生する最小の単位をトークンと言います。区切る文字によっては更に小さな意味を持つこともありますが、区切り文字毎に文字を抜き出そうとする文字分割処理そのものをトークンと呼んでいます。従って、関数名にはtokenのtokをとったような関数名が使われます。これまでの関数もそうでしたが、やっぱりいろんな種類のstrtok関数が準備されていまして…<br /> strtok、_strtok_l、wcstok、_wcstok_l、_mbstok、_mbstok_l ,<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/2c8d19sb.aspx<br /> strtok_s、_strtok_s_l、wcstok_s、_wcstok_s_l、_mbstok_s、_mbstok_s_l<br /> http://msdn.microsoft.com/ja-jp/library/vstudio/ftsafwz3.aspx<br /> 比較関数よりは少ないけど、やっぱりマルチバイト版、マルチバイト2バイト文字対応版、ワイド文字版、それに_sをつけた文字列長を指定するセキュア版と個別ロケール指定をする_lのロケール版があります。_l版についてはココまで使い方を触れてこなかったのですが、 <syntaxhighlight lang="cpp"> _locale_t locale; locale = _tsetlocale(LC_ALL, _T("Japanese")); </syntaxhighlight> として、localeという変数に_locale_t型の値を_tsetlocaleの返り値として格納しておいたものを関数の最後の引数にします。<br /> コマンドプロンプトで動作確認してるだけの段階でlocale変数を利用しても、文字化けしか起こせないと思うので、テキスト出力とかを覚えてから試してみるといいかもしれません。<br /> strtok系の関数では主要な引数が2つで、第1引数には区切り文字を含んだ大元の文字列変数の先頭アドレスの値。第2引数には区切り文字の先頭アドレスの値。","のように文字列リテラルを直接指定することもできますし、複数の区切り文字を含めて",/"とすることもできます。このような文字列が格納されてる変数の先頭アドレスを含んだポインタ変数あるいは、アドレスを返す配列名を指定すること(結局ポインタ変数みたいなものですが…)ができます。第1引数の文字列は書き換え可能な変数でないと駄目です。const char[]="…"のように定義している書き換えできない変数を引数にするとエラーになります。なぜならば、この関数は第2引数で指定している区切り文字を発見したら、その文字が格納されているアドレス部分、配列要素部分の中身を文字列終端を意味する\0に書き換えるからです。つまり、第1引数は、元の状態ではなくなるので、あらかじめバックアップが必要ならコピーをして、保管しておかなければなりません。そして、区切り文字が見つかると先頭アドレスから\0に置き換えた部分までの文字列を返り値として処理を終了します。<br /> え?1つ目以降の区切り文字の結果は?<br /> そうですよね…。2回目の区切り文字探索以降について、この関数の使い方は特殊でして、最初の1回目の区切り文字探索時は上記に記述したような引数で良いのですが、2回目以降の区切り文字探索では第1引数にNULLを設定し、最初に探索した際に\0置き換えた区切り文字の次のアドレスから、第2引数で指定した区切り文字を探索します。それで見つかった区切り文字をまた\0に置き換えて、探索開始アドレスから、\0までの文字列を返り値として処理が終わります。<br /> え?それ以降は?<br /> そうですよね…。探索の結果、区切り文字がみつからなくなるまで、繰り返すようなプログラムにして、ひとつづつ掘り起こすという地味な処理になります。 結果を文字列配列に格納したい場合は、自分で文字列配列を準備して、順番に格納しなければならないのです。区切り文字が何回現れて、いくつの文字が区切られた文字列が返ってきたのかも知りたい場合は、自分で回数を記録する処理が必要になります。<br /> Perlなら見つかった分だけ勝手に配列を作ってくれるような関数だったぞ!って思っている人もおられるかもしれませんが、C++ではそこまで便利な標準関数はないです。ご自分でどうぞお好きなように使って下さい。みたいな感じ?そういうことです。2回目以降で元の文字列を指定せず、NULLを指定することからも、察知できることですが、二つ以上の区切り文字を含めた文字列を交互に、作業することもできませんのであしからず。一つ目が終わってから次の文字列って感じです。不思議な仕組みですよね。想像するに、文字列の後ろからなんらかの文字が現れて次に現れる\0がトークン検索開始位置の文字列になってるのかもしれません。このあたりは実験してみることによってあきらかになるかと思います。<br /> 区切り文字として複数の文字を指定できますが、それぞれ1文字が独立した区切り文字ですので、// のような2文字以上で構成される区切り文字はこの関数だけでは対応できません。新しい手法が必要になります。 <syntaxhighlight lang="cpp" line start="1"> #include <iostream> #include <tchar.h> #include <mbstring.h> //#include <locale.h> int main() { _tsetlocale(LC_ALL, _T("Japanese")); _locale_t locale; locale = _create_locale(LC_ALL, "Japanese"); int iCmpComma=0; int iCmpYen=0; int iCmpSlash=0; int iChartCommaCnt=0; TCHAR *cStr0 = _T("Sweet Refrain/Perfume,雨のち晴レルヤ/ゆず,東京デスティニー/ポルノグラフィティ,\\熱愛発覚中/椎名林檎と中田ヤスタカ(CAPSULE),STORY OF MY LIFE/ONE DIRECTION,THE SEVEN SEAS/THE BAWDIES,手紙/ナオト・インティライミ,SLY/RIP SLYME,閃光 feat10-FEET/東京スカパラダイスオーケストラ,風は西から/奥田民生,DIAMOND SKIN/GLAY,SO RIGHT/三代目 J Soul Brothers from EXILE TRIBE,White Winter Love。/ハジ→,APPLAUSE/LADY GAGA,ピタカゲ from「COUP D'ETAT[+ONE OF A KIND&HEARTBREAKER]」/G-DRAGON (from BIGBANG),LEMON/The Birthday,もったいないとらんど/きゃりーぱみゅぱみゅ,僕らの物語/GReeeeN,Lily/Dragon Ash,START IT AGAIN/AK-69,Very Merry Xmas/東方神起,SURVIVAL/EMINEM,ウォーリーヒーロー/KANA-BOON,あなたへ/エレファントカシマシ,キラーボール/ゲスの極み乙女。,Babies are popstars/松任谷由実,ROCK N ROLL(日本語字幕入り)/AVRIL LAVIGNE,HOT SHOT/GENERATIONS from EXILE TRIBE,守ってあげたい/JUJU,3 2 1/SHINee,Always/斉藤和義,ファンファーレがきこえる/Base Ball Bear,X'masラブストーリー。/ソナーポケット,Missing/androp,ラストバージン/RADWIMPS,エデン(lyric ver)/Aqua Timez,クルクル/e-girls,WHO'S NEXT/SiM,Time goes by/URATA NAOYA,Bi-Li-Li Emotion/Superfly,One day/TOKYO No1 SOUL SET,粉雪/BENI,FEEVEER/MO'SOME TONEBENDER,No525300887039/supercell,Hello\\,999/N'夙川BOYS,Every Hero/kaho,黒猫?Adult Black Cat?/Acid Black Cherry,指でキスしよう/東京カランコロン,m@u/後藤まりこ,海と花束/きのこ帝国"); TCHAR *pcStr0 = new TCHAR[(_tcslen(cStr0)) + 1]; TCHAR *pcStr1 = new TCHAR[(_tcslen(cStr0)) + 1]; TCHAR *pcStr2 = new TCHAR[(_tcslen(cStr0)) + 1]; TCHAR *pcStrTmp; TCHAR *pcStrTmp2; TCHAR *tcharComma = _T(","); TCHAR *tcharYen = _T("\\"); TCHAR *tcharSlash = _T("/"); for(unsigned int i = 0; i < _tcslen(cStr0); i++){ iCmpComma = _tcsncmp(&cStr0[i], tcharComma, 1); if(i > 0){ iCmpYen = _tcsncmp(&cStr0[i - 1] , tcharYen, 1);//コンマ区切りだけど曲名やアーチスト名そのものに,が使われている場合は //予めデータを\,のようにエスケープするというデータ規則が必要。,の前に\が無いか確認して配列サイズを確保。 } if( iCmpComma == 0 && iCmpYen != 0){ iChartCommaCnt++; } } TCHAR ***ppcStrChart = new TCHAR**[iChartCommaCnt + 1]; TCHAR **ppcStrChartTmp = new TCHAR*[iChartCommaCnt + 1]; for(int i = 0; i < iChartCommaCnt + 1;i++){ *(ppcStrChart + i) = new TCHAR*[2];//曲名とアーチスト名の2要素固定 } TCHAR *next_token1 = NULL; TCHAR *next_token2 = NULL; _tcsncpy_s(pcStr0, _tcslen(cStr0) + 1,cStr0, _tcslen(cStr0) + 1);//ココ! pcStr1 = _tcstok_s(pcStr0,_T(","), &next_token1);//establish 1回目の呼び出し { int i = 0; bool bStopIncriment = false; bool bStopIncriment2 = false; while(pcStr1 != NULL && i < (iChartCommaCnt + 1)){ if (bStopIncriment)//区切り文字の前に\が見つかった場合はiを加算しない。 { pcStrTmp = new TCHAR[_tcslen(ppcStrChartTmp[i]) + 1];//現在の文字列最後に区切り文字ではない,があるtmp文字列値バックアップをとるための容量を確保。 _tcsncpy_s(pcStrTmp, _tcslen(ppcStrChartTmp[i]) + 1, ppcStrChartTmp[i], _tcslen(ppcStrChartTmp[i]) + 1 );//そしてバックアップ変数へコピー delete[] ppcStrChartTmp[i];//tmp値を一旦クリア。 ppcStrChartTmp[i] = new TCHAR[_tcslen(pcStrTmp) + _tcslen(pcStr1) + 1];//もう一度容量を確保しなおす。バクアップ変数の長さ+次の区切り文字までの長さ _tcsncpy_s(ppcStrChartTmp[i], _tcslen(pcStrTmp) + _tcslen(pcStr1) + 1 ,pcStrTmp, _tcslen(pcStrTmp));//バックアップ変数と今回の区切り文字を繋ぐ。 _tcsncat_s(ppcStrChartTmp[i], _tcslen(pcStrTmp) + _tcslen(pcStr1) + 1 ,pcStr1, _tcslen(pcStr1));//バックアップ変数と今回の区切り文字を繋ぐ。 _tprintf(_T("i=%2d,ChartTmp1=%s; StrTemp=%s;\n"),i,ppcStrChartTmp[i],pcStrTmp); delete[] pcStrTmp;//バックアップ変数は利用終了。解放。 } iCmpYen = _tcsncmp(&pcStr1[_tcslen(pcStr1)-1],tcharYen,1);//お次の区切り文字は,区切りにしたpcStr1の最後の文字は\ではなかったか確認? if(iCmpYen != 0){ //\以外の通常処理 if(!bStopIncriment){ ppcStrChartTmp[i] = new TCHAR[_tcslen(pcStr1) + 1];//区切り文字の長さで文字配列配列i番目を確保 _tcsncpy_s(ppcStrChartTmp[i],_tcslen(pcStr1) + 1,pcStr1,_tcslen(pcStr1) + 1);//正式な区切り文字なので、区切りまでをコピーして格納。i番目の処理は終了。 } pcStrTmp2 = new TCHAR[_tcslen(ppcStrChartTmp[i]) + 1]; _tcsncpy_s(pcStrTmp2,_tcslen(ppcStrChartTmp[i]) + 1,ppcStrChartTmp[i],_tcslen(ppcStrChartTmp[i]) + 1);//正式な区切り文字なので、区切りまでをコピーして格納。i番目の処理は終了。 ppcStrChart[i][0] = new TCHAR[_tcslen(pcStrTmp2) + 1]; //完全な入れ子状態。, 区切り処理を / 区切り処理に変えただけ。関数化すればスッキリする。けどそんな関数を作るのが目的ではないので、敢えてコレ。***************** pcStr2 = _tcstok_s(pcStrTmp2, _T("/"), &next_token2);//establish 1回目の呼び出し while(pcStr2 != NULL){ if(bStopIncriment2){ pcStrTmp = new TCHAR[_tcslen(ppcStrChart[i][0]) + 1];//現在の文字列最後に区切り文字ではない,があるtmp文字列値バックアップをとるための容量を確保。 _tcsncpy_s(pcStrTmp, _tcslen(ppcStrChart[i][0]) + 1, ppcStrChart[i][0], _tcslen(ppcStrChart[i][0]) + 1 );//そしてバックアップ変数へコピー delete[] ppcStrChart[i][0];//tmp値を一旦クリア。 ppcStrChart[i][0] = new TCHAR[_tcslen(pcStrTmp) + _tcslen(pcStr2) + 1];//もう一度容量を確保しなおす。バクアップ変数の長さ+次の区切り文字までの長さ _tcsncpy_s(ppcStrChart[i][0], _tcslen(pcStrTmp) + _tcslen(pcStr2) + 1 ,pcStrTmp, _tcslen(pcStrTmp));//バックアップ変数と今回の区切り文字を繋ぐ。 _tcsncat_s(ppcStrChart[i][0], _tcslen(pcStrTmp) + _tcslen(pcStr2) + 1 ,pcStr2, _tcslen(pcStr2));//バックアップ変数と今回の区切り文字を繋ぐ。 delete[] pcStrTmp;//バックアップ変数は利用終了。解放。 } iCmpSlash = _tcsncmp(&pcStr2[_tcslen(pcStr2) - 1],tcharSlash,1); if(iCmpSlash != 0){ if(!bStopIncriment2){ ppcStrChart[i][0] = new TCHAR[_tcslen(pcStr2) + 1]; _tcsncpy_s(ppcStrChart[i][0],_tcslen(pcStr2) + 1,pcStr2,_tcslen(pcStr2) + 1);//正式な区切り文字なので、区切りまでをコピーして格納。i 0番目の処理は終了。 } bStopIncriment2 = false; } else{ ppcStrChart[i][0] = new TCHAR[_tcslen(pcStr2) + 1];//まずは区切り文字までの長さより1文字、短い領域を確保。 _tcsncpy_s(ppcStrChart[i][0],_tcslen(pcStr2) + 1 ,pcStr1,_tcslen(pcStr2) - 1);//[*]~[*] [\][/][\0]の\以降を削ってコピー。[*]~[*][\0]になる。 _tcsncat_s(ppcStrChart[i][0],_tcslen(pcStr2) + 1 ,tcharSlash,_tcslen(tcharSlash) + 1);//カンマを付け足す。[*]~[*][/][\0]になる。 bStopIncriment2 = true; } pcStr2 = _tcstok_s(NULL,_T("/"), &next_token2);//2回目以降の呼び出し ppcStrChart[i][1] = new TCHAR[_tcslen(pcStr2) + 1]; _tcsncpy_s(ppcStrChart[i][1], _tcslen(pcStr2) + 1, pcStr2, _tcslen(pcStr2) + 1); pcStr2 = _tcstok_s(NULL,_T("/"), &next_token2);//2回目以降の呼び出し } //完全な入れ子状態ここまで************************************************************************************************************************************** i++; bStopIncriment = false; delete pcStrTmp2; } else{ //\なら,は区切りではないので、ppcStrChartTmp[i]を再作成して、1文字分短くして、\,→,と扱いtmpへ格納。 ppcStrChartTmp[i] = new TCHAR[_tcslen(pcStr1) + 1];//まずは区切り文字までの長さより1文字、短い領域を確保。 _tcsncpy_s(ppcStrChartTmp[i],_tcslen(pcStr1) + 1 ,pcStr1,_tcslen(pcStr1) - 1);//[*]~[*] [\][,][\0]の\以降を削ってコピー。[*]~[*][\0]になる。 _tcsncat_s(ppcStrChartTmp[i],_tcslen(pcStr1) + 1 ,tcharComma,_tcslen(tcharComma) + 1);//カンマを付け足す。[*]~[*][,][\0]になる。 bStopIncriment = true; } pcStr1 = _tcstok_s(NULL,_T(","),&next_token1);//2回目以降の呼び出し } } _tprintf(_T("{| style=\"color:black; background-color:#ffffff;\" cellpadding=\"3\" cellspacing=\"0\" border=\"1\"\n")); for(int i = 0; i < iChartCommaCnt;i++){ _tprintf(_T("|%s\n|%s\n|-\n"),ppcStrChart[i][0],ppcStrChart[i][1]); } _tprintf(_T("|%s\n|%s\n|}\n"),ppcStrChart[iChartCommaCnt][0],ppcStrChart[iChartCommaCnt][1]); printf("%d\n",iChartCommaCnt); for(int i = 0;i < iChartCommaCnt + 1;i++){ delete[] *(ppcStrChartTmp + i); } delete[] ppcStrChartTmp; for(int i = 0;i < iChartCommaCnt + 1 ;i++){ for(int j = 0;j < 2 ;j++){ delete[] *(*(ppcStrChart + i) + j); } } for(int i = 0;i < iChartCommaCnt + 1 ;i++){ delete[] *(ppcStrChart + i); } delete[] ppcStrChart; delete[] pcStr0; delete[] pcStr1; delete[] pcStr2; return 0; } </syntaxhighlight> という具合にtcstok_s関数を使えば、並列してトークン処理が進められるようです。第3引数の参照というC++独自の型を使って、44行目 78行目での最初の呼び出し(エスタブリッシュとも表現します。エスタブリッシュショットというと撮影なんかでワンシーンの手前に一枚絵の風景絵を置くことで、時間帯を表現したりする手法を指します。夜景がシーンの前に入れば室内に映像が切り替わっても夜の出来事であるように示唆するものです。)をして、111、114、131行目のように連続して現れるであろう区切り文字を検索します。111,114行目では、もう区切り文字が現れることがないことがわかっているのですが、2個目のトークンを取得するために実行したり、ループ処理を終わらせるために再度、実行したりという手法で使っています。アイデア次第でなんでもありです。最初にカンマ区切りでトークンを取得するのですが、その間で、さらにカンマ区切りトークンの中に必ず一度現れる、スラッシュによるトークン処理を入れこんでいます。区切り文字が違うだけで全く同じ処理です。こういうプログラム記法は普通はしません。通常は、関数のようなサブプログラムにして、関数を呼び出すことで同じ処理になるように記述します。C++の場合は関数でなくても、クラスのメンバ関数にしても良い訳です。結局同じことですが…。<br /> このような下手くそなプログラムを動かした結果が以下の通りになります。 {| style="color:black; background-color:#ffffff;" cellpadding="3" cellspacing="0" border="1" |Sweet Refrain |Perfume |- |雨のち晴レルヤ |ゆず |- |東京デスティニー |ポルノグラフィティ |- |\熱愛発覚中 |椎名林檎と中田ヤスタカ(CAPSULE) |- |STORY OF MY LIFE |ONE DIRECTION |- |THE SEVEN SEAS |THE BAWDIES |- |手紙 |ナオト・インティライミ |- |SLY |RIP SLYME |- |閃光 feat.10-FEET |東京スカパラダイスオーケストラ |- |風は西から |奥田民生 |- |DIAMOND SKIN |GLAY |- |SO RIGHT |三代目 J Soul Brothers from EXILE TRIBE |- |White Winter Love。 |ハジ→ |- |APPLAUSE |LADY GAGA |- |ピタカゲ from「COUP D'ETAT[+ONE OF A KIND&HEARTBREAKER]」 |G-DRAGON (from BIGBANG) |- |LEMON |The Birthday |- |もったいないとらんど |きゃりーぱみゅぱみゅ |- |僕らの物語 |GReeeeN |- |Lily |Dragon Ash |- |START IT AGAIN |AK-69 |- |Very Merry Xmas |東方神起 |- |SURVIVAL |EMINEM |- |ウォーリーヒーロー |KANA-BOON |- |あなたへ |エレファントカシマシ |- |キラーボール |ゲスの極み乙女。 |- |Babies are popstars |松任谷由実 |- |ROCK N ROLL(日本語字幕入り) |AVRIL LAVIGNE |- |HOT SHOT |GENERATIONS from EXILE TRIBE |- |守ってあげたい |JUJU |- |3 2 1 |SHINee |- |Always |斉藤和義 |- |ファンファーレがきこえる |Base Ball Bear |- |X'masラブストーリー。 |ソナーポケット |- |Missing |androp |- |ラストバージン |RADWIMPS |- |エデン(lyric ver) |Aqua Timez |- |クルクル |e-girls |- |WHO'S NEXT |SiM |- |Time goes by |URATA NAOYA |- |Bi-Li-Li Emotion |Superfly |- |One day |TOKYO No.1 SOUL SET |- |粉雪 |BENI |- |FEEVEER |MO'SOME TONEBENDER |- |No.525300887039 |supercell |- |Hello,999 |N'夙川BOYS |- |Every Hero |kaho |- |黒猫?Adult Black Cat? |Acid Black Cherry |- |指でキスしよう |東京カランコロン |- |m@u |後藤まりこ |- |海と花束 |きのこ帝国 |} 何コレ?って思いました?実はMediaWikiの表形式に変換するプログラムだったりして、出力結果をコピペすると、こういう表になるということです。これは某番組の先週のヒットチャートTOP50ですね。SuperCellのNo.って曲はカッコいいね。曲名の数字は読まなくていいらしい。椎名林檎にきゃりーぱみゅぱみゅ、Greeeen、ゆず、Perfume、東京スカパラダイスオーケストラ。最高っす( ・∀・)b意外と10位以下のあまり、もてはやされない曲でいいのあったりする。JPOPはある程度のカタチがあるよね。そのカタチにはまると、なんか好きな感じになる。歌声だったり、曲の構成だったり、意外性も案外と新しいファクターだよ。この意外性をもとめてるのが若い世代なのかもしれないね。でも、無理しないで王道ってのもいいと思うよ。みんなが好きそうな曲作るってのは、それはそれで凄い事。一部の人間の心を捉える曲もあっていいけど、やっぱ前にでれないのが現実。その間をとってる人もいれば、かたくなに自分のスタイルを貫く人もいる。お金儲け主義の曲って言われてもいいじゃん。みんなが好きな曲ってことだからね。みんなの心を捉えないとお金にならないのが音楽業界。音楽を作りもしないレーベル側に搾取される部分ってのは、なんだかもどかしいよね。でも、育ててもらった恩とか、準備してもらった機材、走り回ってくれるスタッフ、その手配をやってるのはレーベルの努力だからね。会社でいうところの特許は会社員が発明して、お金は8割くらい会社が持っていくっていうそんな感じ。研究させてもらえる環境を提供してるだけでもありがたいと思いなさいということです。それが嫌なら自分で会社たててやってみ?ろくなことなんないぜ?ってそんな感じ。自分で音楽事務所たててうまくいく人なんてそうそういないんだよ。オレは、なんかもうそういうのどうでもよくなってきて、惰性で人生を回転させてるだけ。うっかり幸せな気分でも向上するような出来事にたどり着けたら、人生っては、それなり頑張れば、それなりになるってことを確信して死ねるんだろうし、そうでないとしたら、まぁやっぱこんなもんだよな人生ってのはって心の隅で感じて、半笑いくらいで死ねるような気がする。この先も、どうでもいい。<br /> 別にプログラムつくりたいわけでもなし、こんな文書かいてんだから、まぁ分かる人には分かるでしょ。それでいい。マルチバイト版とマルチバイト2バイト対応版の動作も確認したいよね。まぁ時間があったらですね。それと表の先頭に - があったら、空白を付け足す処理と 文字列の中に| があったら、&#x7c;に置き換える処理を入れないと、 mediawikiのXHTML表記の表にならないので、もう少し改良が必要です。今回はたまたま、N'夙川BOYS(ん しゅくがわ ボーイズ)の曲名に , が使われていたので、流石にカンマ区切りのトークン処理を不完全にさせておくのはまずいと思い、ここまでで記述してきた文字列操作だけを使って、対応版のサンプルプログラムを作っておきました。N'夙川BOYS恐るべし!Hello,999か…。曲名って何でもありの自由空間だから規制がない。Unicodeで全部表せたらいいほう。なんかよくわからない記号とか使うこともあるし。なんらかの規制がないとデータベース化する人は大変だろうなぁ。 ※文字列配列を2次元配列に、つまり3次元配列にしたあたりから、動的なメモリの解放処理ができなくなった(;´・д・)ナンデ。スキル不足でした。役に立ちそうもないし、挫折かな。変に動的なメモリ確保に拘ったのはコレが初めてだから、ショウガナイか。できるとおもってたけど出来ない。そういうことなのかもしれない。一番したの層の文字列事態の解放はできるんですけど、アドレスが格納された部分の解放を記述するとコンパイルエラーにはならないけど、実行時にプログラムが止まる。 ほんとは delete[] *(ppcStrChart + i); ってやって50個の配列に要素[0]と[1]っていうのがぶら下がっているのを解放して、最後に delete[] ppcStrChart ってな具合にしなきゃいけいないはずなんですけど…strtokを使うとゴミが残りやすいのかな?解放できなくなる。生成した直後なら消せるから、やっぱなんかあるなコレ。リファレンス書くつもりがどんどん疑問が増えて課題が増えてるという…無力だな。また時間があるときにでも、原因を調べてみよう。恐るべしstrtok…。しばらくは、OS側にあとかたづけは任せてみる。ごめんなさい。ときどき再起動しとけばいいのかな…(´Д`;) おそらくは、一度生成したものを再作成するかもしれないという作り方に問題があるのかもしれない。文字列の長さが確定してから容量を確保するようなプログラムにするべきなんだろうね。次から気を付ける。って今回のサンプルはなおさないらしい。コイツ。 と悩んでおりましたが、解決しました。サンプルプログラムも更新済みなので、なんのこっちゃわからないと思いますが、配列は使用する領域よりひとつ多くとっておかないとdeleteできなくなるみたいです。文字列の終端にあるであろう\0と同じですね。ヌルポインターになるまで消去するということかもしれません。TOP50のランキングなのでTCHAR ***ppcStrChart = new TCHAR**[iChartCommaCnt];としてiChartCommaCnt=49の大きさ50の配列にしていましたが、TCHAR ***ppcStrChart = new TCHAR**[iChartCommaCnt '''+ 1'''];としたところ、プログラムの最後に記述したdelete[] 関数が動作するようになりました。ふぅ。同じように曲名とアーチスト名ということで*(ppcStrChart + i) = new TCHAR*[1];としていましたが、ここも*(ppcStrChart + i) = new TCHAR*['''2'''];ですね。消すときは、ひとつ少ない値のループ回数になっています。for(int j = 0;j < 2 ;j++)のとおりです。少しすっきりしたけど、なんつうか基本中の基本も知らなかった。いかに動的なメモリの確保をやってこなかったかってことか考えさせられます。プログラムの中でガッツリ確保してました。面倒だもん。でも、ちょっと不思議。それこそなんかゴミが残りそうだけどねぇ。結局また調べなきゃいけないのか(;´・д・)。でも、まぁ上のレベルの配列を消したときに、ぶら下がってる配列が最後まで消えるんだから、普通に考えても消えるわな。本当にそうなのかという、確認だけか。大変ではないね。次の事に進もう。日々、勉強だねぇ。つうか、手遅れ的な感じが否めない。最近、何を学んでも手遅れだと感じてしまう。いやいや、知らないままよりはいいか。ポジティブ。ポジティブ。ん~でも。なんつうか60過ぎてから、プロサッカー選手を目指すみたいな要素も含まれてるような気もする。無理だろみたいなね。プログラムは、まぁ歳食ってからでもやってていいから、気付くのが遅くてもいいことにしとこかな。 =='''文字列の型変換'''== 文字列の型にはchar/*char(LPSTR)、WCHAR/*WCHAR(LPWSTR)、TCHAR/*TCHAR(LPTSTR)がありました。これに変更できない文字列としてconst付きで定義された文字列がありました。これらの型に収められた文字列を相互にやり取りする手法について考えようと思います。文字列操作自体はどれか一つの型を採用するのですが、誰かが作ったクラスやDLLはどの文字列の型を採用しているかはわかりません。あらゆる型から、目的の型に変換できないと、ひとつの型に統一して文字列を操作するということができないので、必須の知識になると思います。そもそもcharやWCHARやTCHARの違いとは何だったのか?覚えていますか?charはマルチバイト文字列、WCHARはワイド文字列、TCHARはプロジェクトの設定に従うマルチバイトあるいはワイド文字列でした。さらに復習しておくと、マルチバイトってのは全角文字を扱うときUnicodeではなくJISコードを拡張した日本語JISコードであり、Windowsならばマイクロソフトが提供しているCP932という文字コードセットで英数字は1バイト、全角文字は2バイトで表される文字、一方、ワイド文字ってのは、UnicodeでUTF-16という方式で英数、日本語は常に2バイトで表現される文字列です(あまり使わない諸外国の文字では4バイトになることもありますが…)。扱う文字コードの違いにより、変数に格納された数値の扱いが異なるため、それぞれの型は動作が異なるため、単純に代入するだけではだめです。だったら最初から代入するような表現だけで変換できるような仕組みを作ってくれれば良かったのですが、そうもいかないようです。そして、ここまで述べてきた型にマイクロソフトが独自に提供しているMFCで定義しているCString(マルチバイトのCStringA、ワイドのCStringW)からの変換や_bstr_t、CComBSTR、basic_string、System::Stringについても考えておきたいと思います。ほかにも独自に考えられた文字列型があれば、その独自の文字列型からの変換についても熟知する必要がありますが、独自の文字列型を提供している人や提供を受けた人が変換について考えれば良いので、ここでは有名どころだけを網羅することにします。マイクロソフトが提供している文字列型の詳細については以下のとおりです。 _bstr_t COM(Component Object Model アプリケーション同士のやりとりをするための技術)サポートクラス BSTR型の文字列クラス<br /> http://msdn.microsoft.com/ja-jp/library/zthfhkd6.aspx<br /> プリプロセッサ:comutil.h<br /> ライブラリ:comsuppw.lib または comsuppwd.lib<br /> BSTR型の解説:http://msdn.microsoft.com/ja-jp/library/ms221069.aspx<br /> 特徴:文字列長を常に保有し続けるBSTR型文字列のための文字列クラス<br /> CComBSTR ATL(Active Template Library MFCの小型版と思っていいと思います。)として提供されるBSTR型の文字列クラス<br /> http://msdn.microsoft.com/ja-jp/library/zh7x9w3f.aspx<br /> basic_string 文字列テンプレートSTL(Standard Template Library ANSI標準テンプレートのライブラリ。)<br /> http://msdn.microsoft.com/ja-jp/library/syxtdd4f.aspx<br /> System::String C++/CLI(Common Language Infrastructure)の文字列型<br /> http://msdn.microsoft.com/ja-jp/library/system.string(v=vs.110).aspx<br /> MFC STL COM ATL CLIと短い略称ですが、それぞれは膨大なライブラリでして、その技術の応用についても、本当は知っていく必要がありますが、ActiveXやらDirectXやらと言い出したらきりがないほど情報技術は歴史が深いし、細かい。Webサービス、SOAP、ネットワーク、暗号化、セキュア…鬼のように沢山の既存技術がある。結構使われてる。ここで触れようとしていること自体もかなり多いけど、それでも、その中のほんの一部に過ぎない。 ちなみにワイド文字とマルチバイト文字の相互変換の簡単な例については<br /> [[C 日本語文字列#マルチバイト文字列、ワイド文字列の相互変換]]<br /> に記述があります。ここでは、更に踏み込んだ変換について触れたいと思います。 というわけで、これくらいできて当然という変換をやってみます。 <syntaxhighlight lang="cpp" line start="1"> #include <string> #include <stdlib.h> #include <iostream> #include <tchar.h> #include <mbstring.h> #include "atlstr.h"//CString,CStringA,CStringWおよびLPTSTR,LPWSTR,LPSTR,LPCTSTR,LPCWSTR,LPCSTRの定義プリプロセッサ #include "cstringt.h"//CStringTの定義プリプロセッサ #include "atlbase.h" //_bstr_t型を利用するプリプロセッサ #include "comutil.h" # ifdef _DEBUG # pragma comment(lib, "comsuppwd.lib") # else # pragma comment(lib, "comsuppw.lib") # endif using namespace std; using namespace System; using namespace System::Runtime::InteropServices; int main() { _tsetlocale(LC_ALL, _T("Japanese")); _locale_t locale; locale = _create_locale(LC_ALL, "Japanese"); //プロジェクトの設定の文字セットでunicode文字セットを使用するに設定しているので、TCHAR→wchar_t型と定義される。 //プロジェクトの設定をかえるとTCHAR→char型になるので、設定によってはTCHAR型に変換する方式を切り替えないとダメ。 //実際の変換処理は#ifdef UNICODEで分けた関数を作る必要がある。 size_t *sizeReturnValue; sizeReturnValue = new size_t; const char *pcStrMoto[] ={"char型の変数 配列要素1","char型の変数 配列要素2"}; const LPSTR pLPSTRStrMoto[] = {"LPSTR型の変数 配列要素1","LPSTR型の変数 配列要素2"}; TCHAR **pptcStrCnv = new TCHAR*[sizeof(pcStrMoto)/sizeof(*pcStrMoto)]; LPTSTR *ppLPTSTRStrCnv = new TCHAR*[sizeof(pcStrMoto)/sizeof(*pcStrMoto)]; _tprintf(_T("文字列の型変換char→TCHAR\n")); for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ #ifdef UNICODE //配列要素i番目の変換後のサイズ取得処理と要素iの実体化と文字列長さ設定。 mbstowcs_s(sizeReturnValue, NULL, 0,pcStrMoto[i], 0); pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; ppLPTSTRStrCnv[i] = new TCHAR[*sizeReturnValue]; //変換処理。 mbstowcs_s(sizeReturnValue, pptcStrCnv[i], *sizeReturnValue, pcStrMoto[i], *sizeReturnValue); mbstowcs_s(sizeReturnValue, ppLPTSTRStrCnv[i], *sizeReturnValue, pcStrMoto[i], *sizeReturnValue); #else //マルチバイト定義の場合はchar型同志のコピーになるので変換不要。 pptcStrCnv[i] = new TCHAR[_tcslen(pcStrMoto[i]) + 1]; ppLPTSTRStrCnv[i] = new TCHAR[_tcslen(pcStrMoto[i]) + 1]; _tcscpy_s(pptcStrCnv[i],_tcslen(pcStrMoto[i]) + 1,pcStrMoto[i]); _tcscpy_s(ppLPTSTRStrCnv[i],_tcslen(pcStrMoto[i]) + 1,pcStrMoto[i]); #endif //出力 _tprintf(_T("要素[%d]\n"),i); for(unsigned int j = 0; j < *sizeReturnValue; j++){ _tprintf(_T("[%2d]=%x,"),j,*(*(pptcStrCnv + i) + j)); } _tprintf(_T("\n%s\n"),*(pptcStrCnv + i)); } _tprintf(_T("\n文字列の型変換TCHAR→char\n")); const TCHAR *ptcStrMoto[] = {_T("TCHAR型の変数 配列要素1"),_T("TCHAR型の変数 配列要素2")}; const LPTSTR pLPTSTRStrMoto[] = {_T("LPTSTR型の変数 配列要素1"),_T("LPTSTR型の変数 配列要素2")}; char **ppcStrCnv = new char*[sizeof(ptcStrMoto)/sizeof(*ptcStrMoto)]; LPSTR *ppLPSTRStrCnv = new char*[sizeof(ptcStrMoto)/sizeof(*ptcStrMoto)]; for(int i = 0; i < (sizeof(ptcStrMoto)/sizeof(*ptcStrMoto)); i++){ #ifdef UNICODE //配列要素i番目の変換後のサイズ取得処理と要素iの実体化と文字列長さ設定。 wcstombs_s(sizeReturnValue, NULL, 0,ptcStrMoto[i], 0); ppcStrCnv[i] = new char[*sizeReturnValue]; ppLPSTRStrCnv[i] = new char[*sizeReturnValue]; //変換処理。 wcstombs_s(sizeReturnValue, ppcStrCnv[i], *sizeReturnValue, ptcStrMoto[i], *sizeReturnValue); wcstombs_s(sizeReturnValue, ppLPSTRStrCnv[i], *sizeReturnValue, ptcStrMoto[i], *sizeReturnValue); #else //マルチバイト定義の場合はchar型同志のコピーになるので変換不要。 ppcStrCnv[i] = new TCHAR[_tcslen(ptcStrMoto[i]) + 1]; ppLPSTRStrCnv[i] = new TCHAR[_tcslen(ptcStrMoto[i]) + 1]; _tcscpy_s(ppcStrCnv[i],_tcslen(ptcStrMoto[i]) + 1,ptcStrMoto[i]); _tcscpy_s(ppLPSTRStrCnv[i],_tcslen(ptcStrMoto[i]) + 1,ptcStrMoto[i]); #endif //出力 _tprintf(_T("要素[%d]\n"),i); for(unsigned int j = 0; j < *sizeReturnValue; j++){ printf("[%2d]=%x,",j,*(*(ppcStrCnv + i) + j)); printf("[%2d]=%x,",j,*(*(ppLPSTRStrCnv + i) + j)); } printf("\n%s\n",*(ppcStrCnv + i)); printf("%s\n",*(ppLPSTRStrCnv + i)); } //_bstr_t,CComBSTR,CString,System::Stringいずれもcharの先頭アドレスを代入すれば格納できる。 _tprintf(_T("\n文字列の型変換char→_bstr_t\n")); _bstr_t bstrt[(sizeof(pcStrMoto)/sizeof(*pcStrMoto))]; for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ bstrt[i] = pcStrMoto[i];//代入するだけ std::cout << bstrt[i] << std::endl; printf("_bstr_t %s\n",(LPCSTR)bstrt[i]); } _tprintf(_T("\n文字列の型変換char→CComBSTR\n")); CComBSTR ccombstr[(sizeof(pcStrMoto)/sizeof(*pcStrMoto))]; for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ ccombstr[i] = pcStrMoto[i];//代入するだけ //マクロにより出力用の変数に文字列を移す必要がある。これはCComBSTR型の決まり。 CW2A printstr(ccombstr[i]); std::cout << printstr << std::endl; printf("CComBSTR %s\n",printstr); } _tprintf(_T("\n文字列の型変換char→CStringA\n")); CStringA cstringa[(sizeof(pcStrMoto)/sizeof(*pcStrMoto))]; for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ cstringa[i] = pcStrMoto[i];//代入するだけ std::cout << cstringa[i] << std::endl; printf("CStringA %s\n",cstringa[i]); } _tprintf(_T("\n文字列の型変換char→CStringW\n")); CStringW cstringw[(sizeof(pcStrMoto)/sizeof(*pcStrMoto))]; for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ cstringw[i] = pcStrMoto[i];//代入するだけ std::wcout << (LPCTSTR)cstringw[i] << std::endl; _tprintf(_T("CStringW %s\n"),(LPCTSTR)cstringw[i]); } _tprintf(_T("\n文字列の型変換char→string\n")); string basicstring[(sizeof(pcStrMoto)/sizeof(*pcStrMoto))]; for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ basicstring[i] = pcStrMoto[i];//代入するだけ cout << basicstring[i] << endl; printf("string %s\n",basicstring[i].c_str()); } _tprintf(_T("\n文字列の型変換char→SystemString\n")); array<String^> ^systemstring = gcnew array<String^>(sizeof(pcStrMoto)/sizeof(*pcStrMoto)); for(int i = 0; i < (sizeof(pcStrMoto)/sizeof(*pcStrMoto)); i++){ char* pcStrTemp = new char[strlen(pcStrMoto[i]) + 1]; strcpy_s(pcStrTemp,strlen(pcStrMoto[i]) + 1,pcStrMoto[i]); System::IntPtr ptr(pcStrTemp);//この関数がconst charの変換に対応していないので、上の2行でconst無しの変数に移し替えた。 systemstring[i] = Marshal::PtrToStringAnsi(ptr);//IntPtrポインタを引数として変換するメソッド。 Console::WriteLine("{0}", systemstring[i]); delete[] pcStrTemp; } } </syntaxhighlight> 上から<br /> char(LPSTR)→TCHAR(LPTSTR)<br /> TCHAR(LPTSTR)→char(LPSTR)<br /> の変換ここでは#ifndef UNICODEディレクティブによりTCHARの扱いをプロジェクトでどのように定義したか?によって動作が切り替わるように処理を組み込んでいます。以前に記述したサンプル[[C 日本語文字列#マルチバイト文字列、ワイド文字列の相互変換]]では、そこまでは言及していませんでした。プロジェクトの設定の文字セットでunicode文字セットを使用するに設定していれば、上側の#ifndef UNICODEから#elseまでに囲まれた部分が処理される。変換が必要かどうか?確認するのがよいです。<br /> その次に<br /> charから_bstr_tやCComBSTRやCStringA、CStringWのような変換について記述しています。このあたりの変数はchar型のポインタを代入するだけで変換をしてくれます。但し、出力するときには少し工夫が必要になります。これはどちらかというと、独自の文字列クラスの仕様によるものなので、それぞれの文字クラスについて学習を進める必要があります。先に示したリンクからそれぞれのクラスについて学習してみて下さい。こちらのサイトでもいつかは触れていきたいですが、まだまだ先になりそうです。<br /> それから、<br /> charからstring、System::Stringへの変換について記述しています。<br /> System::Stringは共通言語ランタイムですので、動作させるにはプロジェクトの設定を変更しないといけません。<br /> しかも、設定を変更しても従来のC言語の記法と共通言語ランタイムの記法を混同させるとVisual C++のコードインテリジェンス機能が完全停止しますのでコード編集が大変になりますので、このサンプルのような混同したプリプロセッサ定義をして無理やり、いろいろな変換のサンプルを記述するのは良くないです。 [[file:IntelliSenseOff.png]] 上記の図のようなエラーになります。共通言語ランタイムとプリプロセッサの混同に関する詳細な条件もまた後程調査ですかね。ほんとに調べるのかは定かでありませんが… ※コードインテリセンスは、例えばにstrcpyのようなよく使う関数を使うときに引数には何を定義すればよいのか、ヒントを与える機能です strcpy( までタイプすると第一引数には char* 型のコピー先の変数、第二引数にはコピー元のchar* 型の変数、第三引数にはコピーする文字の配列の長さを指定するべきだとポップアップ表示がされます。クラス変数や構造体変数を使う場合にも 変数名. あるいは変数名-> までタイプするとメンバ変数や、メソッドのリストが表示されます。メソッドの引数のヒントも関数と同様にポップアップ表示されます。 複数の文字列プリプロセッサを混同しないのが本来のやりかたになります。System::Stringへのchar変数の代入だけは複数の処理ステップが必要になります。System::String用に準備されているメソッドがconst char*の引数に対応していなかったり、独自の仕組みでしか引数をとることができないからです。ちなみに、文字列の配列でなければ、もう少し簡単に変換ができて、<br /> System::String ^systemstring = gcnew String(char*型変数);<br /> のように記述するだけで、コンストラクタの初期値によって変換自体は完了させることができます。と、ここまでchar型からの変換だけで、ずいぶんと長い説明になってしまいました。このあたりの配列を使った場合の文字列変換についてまとめている文書は意外と少ないと思います。次は逆変換ですかね。こっちのほうが大変なんだよね。そしたら次はTCHARからの変換か…で、その逆変換。ふむー。先は長い。普段こんなに変換ばっかりやんないので、この記事キツイっすね。なんでこんなん書いてるんやろ。役に立つんか?ほんまに… マネージコードを利用するために実施した設定変更<br /> C/C++ <br /> 全般<br /> デバッグ情報の形式 プログラムデータベース /Zi ← エディットコンティニュのプログラムデータベース /ZI<br /> 共通言語ランタイム サポート 共通言語ランタイムサポート /clr ←共通言語ランタイムをサポートしない<br /> コード生成<br /> 最小リビルドを有効にする。 いいえ /Gm- ←はい /Gm<br /> C++の例外を有効にする はい SEHの例外あり /EHa ← はい /EHsc<br /> 基本ランタイムチェック 規定 ← 両方 /RTC1<br /> VisualStudioのコードインテリセンスを有効にしたままC++とC++/CLI(共通言語)の勉強したい場合は、C++/CLIプロジェクトでもC++言語は使えるので、プロジェクトの作成からやりなおしてみると良いです。 更に変換を続けたのものが以下になります。 <syntaxhighlight lang="cpp" line start="1"> _tsetlocale(LC_ALL, _T("Japanese")); _locale_t locale; locale = _create_locale(LC_ALL, "Japanese"); const char *pcStrMoto[] ={"char型の変数 配列要素1","char型の変数 配列要素2"}; const LPSTR pLPSTRStrMoto[] = {"LPSTR型の変数 配列要素1","LPSTR型の変数 配列要素2"}; const TCHAR *ptcStrMoto[] = {_T("TCHAR型の変数 要素1"),_T("TCHAR型の変数 要素2")}; const LPTSTR pLPTSTRStrMoto[] = {_T("LPTSTR型の変数 要素1"),_T("LPTSTR型の変数 要素2")}; size_t *sizeReturnValue; sizeReturnValue = new size_t; int *pnStrArrayElement; pnStrArrayElement = new int; *pnStrArrayElement = sizeof(ptcStrMoto)/sizeof(*ptcStrMoto); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・TCHAR→char変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("文字列の型変換TCHAR→char\n")); char **ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 LPSTR *ppLPSTRStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 #ifdef UNICODE //変換 for(int i = 0; i < *pnStrArrayElement; i++){ wcstombs_s(sizeReturnValue, NULL, 0,ptcStrMoto[i], 0); ppcStrCnv[i] = new char[*sizeReturnValue]; ppLPSTRStrCnv[i] = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, ppcStrCnv[i], *sizeReturnValue, ptcStrMoto[i], *sizeReturnValue); wcstombs_s(sizeReturnValue, ppLPSTRStrCnv[i], *sizeReturnValue, ptcStrMoto[i], *sizeReturnValue); } #else //無変換 for(int i = 0; i < *pnStrArrayElement; i++){ ppcStrCnv[i] = new char[*sizeReturnValue]; ppLPSTRStrCnv[i] = new char[*sizeReturnValue]; _tcscpy_s(ppcStrCnv[i], _tcslen(ptcStrMoto[i]) + 1, ptcStrMoto[i]); _tcscpy_s(ppLPSTRStrCnv[i], _tcslen(ptcStrMoto[i]) + 1, ptcStrMoto[i]); } #endif //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //LPSTR出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppLPSTRStrCnv + i)); } printf("%d\n", sizeof(**ppcStrCnv)); printf("%d\n", sizeof(*ppcStrCnv)); printf("%d\n", sizeof(ppcStrCnv));//動的に確保した配列の大きさは取得できない。 printf("%d\n", sizeof(**ptcStrMoto)); printf("%d\n", sizeof(*ptcStrMoto)); printf("%d\n", sizeof(ptcStrMoto)); //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); delete[] *(ppLPSTRStrCnv + i); } delete[] ppcStrCnv; delete[] ppLPSTRStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→char //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→char\n")); const _bstr_t bstrtOrigin[] = {_T("_bstr_t型の変数 配列要素1"),_T("_bstr_t型の変数 配列要素2"),_T("_bstr_t型の変数 配列要素3")}; printf("%d\n", sizeof(*bstrtOrigin)); printf("%d\n", sizeof(bstrtOrigin)); *pnStrArrayElement = sizeof(bstrtOrigin)/sizeof(*bstrtOrigin); ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ *sizeReturnValue = strlen((char*)bstrtOrigin[i]) + 1; ppcStrCnv[i] = new char[*sizeReturnValue]; strcpy_s(ppcStrCnv[i], *sizeReturnValue, (char*)bstrtOrigin[i]); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); } delete[] ppcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→TCHAR //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→TCHAR\n")); TCHAR **pptcStrCnv = new TCHAR*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ *sizeReturnValue = _tcslen((TCHAR*)bstrtOrigin[i]) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, (TCHAR*)bstrtOrigin[i]); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ _tprintf(_T("%s\n"),*(pptcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(pptcStrCnv + i); } delete[] pptcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→CComBSTR(マルチバイト文字ワイド文字両対応 プロジェクト設定に従う) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→CComBSTR\n")); CComBSTR *pccombstr_StrCnv = new CComBSTR[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pccombstr_StrCnv[i] = (char*)bstrtOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 CW2A printstr(*(pccombstr_StrCnv + i)); printf("%s\n",printstr); //無変換出力 _tprintf(_T("%s\n"),*(pccombstr_StrCnv + i)); } //動的確保変数の解放 delete[] pccombstr_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→CStringA(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→CStringA\n")); CStringA *pcstringa_StrCnv = new CStringA[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringa_StrCnv[i] = (char*)bstrtOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pcstringa_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringa_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→CStringW(ワイド文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→CStringW\n")); CStringW *pcstringw_StrCnv = new CStringW[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringw_StrCnv[i] = (char*)bstrtOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //wchar_t出力 wprintf(L"%s\n",pcstringw_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringw_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→string(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→string\n")); string *pstring_StrCnv = new string[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pstring_StrCnv[i] = (char*)bstrtOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pstring_StrCnv[i].c_str()); } //動的確保変数の解放 delete[] pstring_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・_bstr_t→SystemString(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→SystemString\n")); array<String^> ^psysstring_StrCnv = gcnew array<String^>(*pnStrArrayElement); //変換 for(int i = 0; i < *pnStrArrayElement; i++){ char* pcStrTemp = new char[strlen((char*)bstrtOrigin[i]) + 1]; strcpy_s(pcStrTemp,strlen((char*)bstrtOrigin[i]) + 1,(char*)bstrtOrigin[i]); System::IntPtr ptr(pcStrTemp); psysstring_StrCnv[i] = Marshal::PtrToStringAnsi(ptr); delete[] pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",psysstring_StrCnv[i]); //TCHAR変換出力 #ifdef UNICODE _tprintf(_T("%s\n"),PtrToStringChars(psysstring_StrCnv[i])); #else _tprintf(_T("%s\n"),psysstring_StrCnv[i]); #endif } //動的確保変数の解放 delete[] psysstring_StrCnv; delete[] sizeReturnValue; delete[] pnStrArrayElement; </syntaxhighlight> _bstr_t型からの変換に関するサンプルを追加しました。 型変換とは関係ない部分になりますが、配列のサイズ確保処理について補足しておきますと、文字列配列の大きさは動的に生成した文字列配列からは取得することはできません。動的に生成したときの大きさをプログラマ自身が管理する必要があります。そのことを知ることができるのが上記の64行目のprintf文です。ここで動的に生成した文字列配列の大きさをsizeof関数で表示していますが、配列の大きさは32bitアプリならば、要素数2つなので4byte*2[配列要素数]=8byte(4byte=32bitでひとつのアドレス ※8bit=1byte)になるはずですが、4byteになっています。これはポインタ変数の大きさ、アドレス記憶変数ひとつ分の大きさになっていて、実際の配列サイズが返ってこないことが確認できます。 話は戻って… 上記のように変換を進めていて気づくことですが、それぞれの型は取り扱える文字コード長が異なります。_bstr_tやCComBSTRはマルチバイト文字とワイド文字の両方に対応していて、プロジェクト設定にしたがって記憶する文字型を切り替えています。CStringAはマルチバイト文字、CStringWはワイド文字です。stringとSystem::Stringはマルチバイト文字を扱うようになっています。したがって、変換時にはマルチバイト文字、ワイド文字変換が必要になるケースと必要ないケース。あるいは、プロジェクトの設定によって決まるケースがあるわけです。そのことから、_bstr_tやCComBSTを利用しておくという、ある程度、文字列の世界を熟知している人だけが選ぶ道があるようにも思えるわけです。マイクロソフトの用意したものを使うにしても賢い選択というのが、その時代、時代によって存在することになります。 開発するプログラムの枠組みによってはマルチバイトやワイド文字といった切り替えは気にしないという人もいるのかもしれません。具体的にどのように変換処理を記述するかについても、そのときそのときで違ってくることもあるのかもしれませんね。 変換の種類がたくさんありますが、wchar_tとcharの変換をおぼえれば、それぞれの特殊な型をchar型に変換する手法とcharからそれぞれの型に変換する手法をマスターすれば、変換手順は長くなる可能性があるものの、とにかくすべてを網羅できるわけです。特殊な型から特殊な型へのダイレクトな変換は覚えなくてもなんとかなる。覚えた方が楽になる。そんな感じです。それぞれの人の考え方にあわせて、覚える量を調節すれば済む話です。 マイクロソフトの説明書にも簡単な変換に関する文書があります。 http://msdn.microsoft.com/ja-jp/library/ms235631(v=vs.110).aspx ここに記述している内容とさほど差はありません。わかりやすい方を参考にしてみて下さい。 では引き続き、変換のサンプルを… <syntaxhighlight lang="cpp" line start="1"> //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→char //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→char\n")); const CComBSTR ccombstrOrigin[] = {_T("CComBSTR型の変数 配列要素1"),_T("CComBSTR型の変数 配列要素2"),_T("CComBSTR型の変数 配列要素3")}; printf("%d\n", sizeof(*ccombstrOrigin)); printf("%d\n", sizeof(ccombstrOrigin)); *pnStrArrayElement = sizeof(ccombstrOrigin)/sizeof(*ccombstrOrigin); ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); *sizeReturnValue = strlen(strtemp) + 1; ppcStrCnv[i] = new char[*sizeReturnValue]; strcpy_s(ppcStrCnv[i], *sizeReturnValue, strtemp); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); } delete[] ppcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→TCHAR //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→TCHAR\n")); pptcStrCnv = new TCHAR*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ #ifdef UNICODE *sizeReturnValue = _tcslen(ccombstrOrigin[i]) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, ccombstrOrigin[i]); #else CW2A strtemp(ccombstrOrigin[i]); *sizeReturnValue = strlen(strtemp) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, strtemp); #endif } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ _tprintf(_T("%s\n"),*(pptcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(pptcStrCnv + i); } delete[] pptcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→_bstr_t(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換_bstr_t→CComBSTR\n")); _bstr_t *pbstrt_StrCnv = new _bstr_t[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); pbstrt_StrCnv[i] = strtemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //無変換出力 printf("%s\n",(char*)pbstrt_StrCnv[i]); _tprintf(_T("%s\n"),(wchar_t*)pbstrt_StrCnv[i]); } //動的確保変数の解放 delete[] pbstrt_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→CStringA(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→CStringA\n")); pcstringa_StrCnv = new CStringA[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); pcstringa_StrCnv[i] = strtemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pcstringa_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringa_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→CStringW(ワイド文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→CStringW\n")); pcstringw_StrCnv = new CStringW[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); pcstringw_StrCnv[i] = strtemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //wchar_t出力 wprintf(L"%s\n",pcstringw_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringw_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→string(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→string\n")); pstring_StrCnv = new string[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); pstring_StrCnv[i] = strtemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pstring_StrCnv[i].c_str()); } //動的確保変数の解放 delete[] pstring_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→SystemString(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→SystemString\n")); psysstring_StrCnv = gcnew array<String^>(*pnStrArrayElement); //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); System::IntPtr ptr(strtemp); psysstring_StrCnv[i] = Marshal::PtrToStringAnsi(ptr); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",psysstring_StrCnv[i]); //TCHAR変換出力 #ifdef UNICODE _tprintf(_T("%s\n"),PtrToStringChars(psysstring_StrCnv[i])); #else _tprintf(_T("%s\n"),psysstring_StrCnv[i]); #endif } //動的確保変数の解放 delete[] psysstring_StrCnv; </syntaxhighlight> 引き続き、変換のサンプルを記述していきます。残るはCComBSTR、CStringA、CStringW、string、System::String基準の変換ですね。 <syntaxhighlight lang="cpp" line start="1"> //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→char //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→char\n")); const CStringA cstringaOrigin[] = {_T("CStringA型の変数 配列要素1"),_T("CStringA型の変数 配列要素2"),_T("CStringA型の変数 配列要素3")}; printf("%d\n", sizeof(*cstringaOrigin)); printf("%d\n", sizeof(cstringaOrigin)); *pnStrArrayElement = sizeof(cstringaOrigin)/sizeof(*cstringaOrigin); ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ *sizeReturnValue = strlen(cstringaOrigin[i]) + 1; ppcStrCnv[i] = new char[*sizeReturnValue]; strcpy_s(ppcStrCnv[i], *sizeReturnValue, cstringaOrigin[i]); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); } delete[] ppcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→TCHAR //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→TCHAR\n")); pptcStrCnv = new TCHAR*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ #ifdef UNICODE mbstowcs_s(sizeReturnValue, NULL, 0,cstringaOrigin[i], 0); pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; mbstowcs_s(sizeReturnValue, pptcStrCnv[i], *sizeReturnValue,cstringaOrigin[i], *sizeReturnValue); #else *sizeReturnValue = strlen(cstringaOrigin[i]) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, cstringaOrigin[i]); #endif } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ _tprintf(_T("%s\n"),*(pptcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(pptcStrCnv + i); } delete[] pptcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→_bstr_t(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→CComBSTR\n")); pbstrt_StrCnv = new _bstr_t[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pbstrt_StrCnv[i] = cstringaOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //無変換出力 printf("%s\n",(char*)pbstrt_StrCnv[i]); _tprintf(_T("%s\n"),(wchar_t*)pbstrt_StrCnv[i]); } //動的確保変数の解放 delete[] pbstrt_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CComBSTR→CStringA(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CComBSTR→CStringA\n")); pcstringa_StrCnv = new CStringA[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ CW2A strtemp(ccombstrOrigin[i]); pcstringa_StrCnv[i] = strtemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pcstringa_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringa_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→CStringW(ワイド文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→CStringW\n")); pcstringw_StrCnv = new CStringW[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringw_StrCnv[i] = cstringaOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //wchar_t出力 wprintf(L"%s\n",pcstringw_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringw_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→string(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→string\n")); pstring_StrCnv = new string[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pstring_StrCnv[i] = cstringaOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pstring_StrCnv[i].c_str()); } //動的確保変数の解放 delete[] pstring_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→SystemString(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→SystemString\n")); psysstring_StrCnv = gcnew array<String^>(*pnStrArrayElement); //変換 for(int i = 0; i < *pnStrArrayElement; i++){ char* pcStrTemp = new char[strlen(cstringaOrigin[i]) + 1]; strcpy_s(pcStrTemp,strlen(cstringaOrigin[i]) + 1,cstringaOrigin[i]); System::IntPtr ptr(pcStrTemp); psysstring_StrCnv[i] = Marshal::PtrToStringAnsi(ptr); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",psysstring_StrCnv[i]); //TCHAR変換出力 #ifdef UNICODE _tprintf(_T("%s\n"),PtrToStringChars(psysstring_StrCnv[i])); #else _tprintf(_T("%s\n"),psysstring_StrCnv[i]); #endif } //動的確保変数の解放 delete[] psysstring_StrCnv; </syntaxhighlight> <syntaxhighlight lang="cpp" line start="1"> //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringW→char //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringW→char\n")); const CStringW cstringwOrigin[] = {_T("CStringW型の変数 配列要素1"),_T("CStringW型の変数 配列要素2"),_T("CStringW型の変数 配列要素3")}; printf("%d\n", sizeof(*cstringwOrigin)); printf("%d\n", sizeof(cstringwOrigin)); *pnStrArrayElement = sizeof(cstringwOrigin)/sizeof(*cstringwOrigin); ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ wcstombs_s(sizeReturnValue, NULL, 0,cstringwOrigin[i], 0); ppcStrCnv[i] = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, ppcStrCnv[i], *sizeReturnValue,cstringwOrigin[i], *sizeReturnValue); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); } delete[] ppcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringW→TCHAR //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringW→TCHAR\n")); pptcStrCnv = new TCHAR*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ #ifdef UNICODE *sizeReturnValue = _tcslen(cstringwOrigin[i]) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, cstringwOrigin[i]); #else wcstombs_s(sizeReturnValue, NULL, 0,cstringwOrigin[i], 0); ppcStrCnv[i] = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, ppcStrCnv[i], *sizeReturnValue,cstringwOrigin[i], *sizeReturnValue); #endif } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ _tprintf(_T("%s\n"),*(pptcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(pptcStrCnv + i); } delete[] pptcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringW→_bstr_t(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→CComBSTR\n")); pbstrt_StrCnv = new _bstr_t[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pbstrt_StrCnv[i] = cstringwOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //無変換出力 printf("%s\n",(char*)pbstrt_StrCnv[i]); _tprintf(_T("%s\n"),(wchar_t*)pbstrt_StrCnv[i]); } //動的確保変数の解放 delete[] pbstrt_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringW→CStringA(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringW→CStringA\n")); pcstringa_StrCnv = new CStringA[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringa_StrCnv[i] = cstringwOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pcstringa_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringa_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringA→CStringW(ワイド文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringA→CStringW\n")); pcstringw_StrCnv = new CStringW[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringw_StrCnv[i] = cstringaOrigin[i]; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //wchar_t出力 wprintf(L"%s\n",pcstringw_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringw_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringW→string(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringW→string\n")); pstring_StrCnv = new string[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ wcstombs_s(sizeReturnValue, NULL, 0,cstringwOrigin[i], 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue,cstringwOrigin[i], *sizeReturnValue); pstring_StrCnv[i] = pcStrTemp; delete[] pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pstring_StrCnv[i].c_str()); } //動的確保変数の解放 delete[] pstring_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・CStringW→SystemString(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換CStringW→SystemString\n")); psysstring_StrCnv = gcnew array<String^>(*pnStrArrayElement); //変換 for(int i = 0; i < *pnStrArrayElement; i++){ wcstombs_s(sizeReturnValue, NULL, 0,cstringwOrigin[i], 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue,cstringwOrigin[i], *sizeReturnValue); System::IntPtr ptr(pcStrTemp); psysstring_StrCnv[i] = Marshal::PtrToStringAnsi(ptr); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",psysstring_StrCnv[i]); //TCHAR変換出力 #ifdef UNICODE _tprintf(_T("%s\n"),PtrToStringChars(psysstring_StrCnv[i])); #else _tprintf(_T("%s\n"),psysstring_StrCnv[i]); #endif } //動的確保変数の解放 delete[] psysstring_StrCnv; </syntaxhighlight> <syntaxhighlight lang="cpp" line start="1"> //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→char //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→char\n")); const string stringOrigin[] = {"string型の変数 配列要素1","string型の変数 配列要素2","string型の変数 配列要素3"}; printf("%d\n", sizeof(*stringOrigin)); printf("%d\n", sizeof(stringOrigin)); *pnStrArrayElement = sizeof(stringOrigin)/sizeof(*stringOrigin); ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ *sizeReturnValue = strlen(stringOrigin[i].c_str()) + 1; ppcStrCnv[i] = new char[*sizeReturnValue]; strcpy_s(ppcStrCnv[i], *sizeReturnValue, stringOrigin[i].c_str()); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); } delete[] ppcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→TCHAR //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→TCHAR\n")); pptcStrCnv = new TCHAR*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ #ifdef UNICODE mbstowcs_s(sizeReturnValue, NULL, 0,stringOrigin[i].c_str(), 0); pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; mbstowcs_s(sizeReturnValue, pptcStrCnv[i], *sizeReturnValue,stringOrigin[i].c_str(), *sizeReturnValue); #else *sizeReturnValue = strlen(stringOrigin[i].c_str()) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, stringOrigin[i].c_str()); #endif } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ _tprintf(_T("%s\n"),*(pptcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(pptcStrCnv + i); } delete[] pptcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→_bstr_t(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→_bstr_t\n")); pbstrt_StrCnv = new _bstr_t[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pbstrt_StrCnv[i] = stringOrigin[i].c_str(); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //無変換出力 printf("%s\n",(char*)pbstrt_StrCnv[i]); _tprintf(_T("%s\n"),(wchar_t*)pbstrt_StrCnv[i]); } //動的確保変数の解放 delete[] pbstrt_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→CComBSTR(マルチバイト文字ワイド文字両対応 プロジェクト設定に従う) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→CComBSTR\n")); pccombstr_StrCnv = new CComBSTR[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pccombstr_StrCnv[i] = stringOrigin[i].c_str(); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 CW2A printstr(*(pccombstr_StrCnv + i)); printf("%s\n",printstr); //無変換出力 _tprintf(_T("%s\n"),*(pccombstr_StrCnv + i)); } //動的確保変数の解放 delete[] pccombstr_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→CStringA(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→CStringA\n")); pcstringa_StrCnv = new CStringA[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringa_StrCnv[i] = stringOrigin[i].c_str(); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pcstringa_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringa_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→CStringW(ワイド文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→CStringW\n")); pcstringw_StrCnv = new CStringW[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pcstringw_StrCnv[i] = stringOrigin[i].c_str(); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //wchar_t出力 wprintf(L"%s\n",pcstringw_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringw_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・string→SystemString(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→SystemString\n")); psysstring_StrCnv = gcnew array<String^>(*pnStrArrayElement); //変換 for(int i = 0; i < *pnStrArrayElement; i++){ char* pcStrTemp = new char[strlen(stringOrigin[i].c_str()) + 1]; strcpy_s(pcStrTemp,strlen(stringOrigin[i].c_str()) + 1,stringOrigin[i].c_str()); System::IntPtr ptr(pcStrTemp); psysstring_StrCnv[i] = Marshal::PtrToStringAnsi(ptr); } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",psysstring_StrCnv[i]); //TCHAR変換出力 #ifdef UNICODE _tprintf(_T("%s\n"),PtrToStringChars(psysstring_StrCnv[i])); #else _tprintf(_T("%s\n"),psysstring_StrCnv[i]); #endif } //動的確保変数の解放 delete[] psysstring_StrCnv; </syntaxhighlight> <syntaxhighlight lang="cpp" line start="1"> //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→char //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換string→char\n")); array<String^> ^sysstringOrigin = gcnew array<String^>{"SystemString型の変数 配列要素1","SystemString型の変数 配列要素2","SystemString型の変数 配列要素3"}; printf("%d\n", sysstringOrigin->Length); *pnStrArrayElement = sysstringOrigin->Length; ppcStrCnv = new char*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); ppcStrCnv[i] = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, ppcStrCnv[i], *sizeReturnValue, wch, *sizeReturnValue); } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ printf("%s\n",*(ppcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(ppcStrCnv + i); } delete[] ppcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→TCHAR //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換SystemString→TCHAR\n")); pptcStrCnv = new TCHAR*[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ #ifdef UNICODE pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); *sizeReturnValue = _tcslen(wch) + 1; pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; _tcscpy_s(pptcStrCnv[i], *sizeReturnValue, wch); #else pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); pptcStrCnv[i] = new TCHAR[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pptcStrCnv[i], *sizeReturnValue, wch, *sizeReturnValue); #endif } //char出力 for(int i = 0; i < *pnStrArrayElement; i++){ _tprintf(_T("%s\n"),*(pptcStrCnv + i)); } //動的確保変数の解放 for(int i = 0;i < *pnStrArrayElement ;i++){ delete[] *(pptcStrCnv + i); } delete[] pptcStrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→_bstr_t(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換SystemString→_bstr_t\n")); pbstrt_StrCnv = new _bstr_t[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue, wch, *sizeReturnValue); pbstrt_StrCnv[i] = pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //無変換出力 printf("%s\n",(char*)pbstrt_StrCnv[i]); _tprintf(_T("%s\n"),(wchar_t*)pbstrt_StrCnv[i]); } //動的確保変数の解放 delete[] pbstrt_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→CComBSTR(マルチバイト文字ワイド文字両対応 プロジェクト設定に従う) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換SystemString→CComBSTR\n")); pccombstr_StrCnv = new CComBSTR[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue, wch, *sizeReturnValue); pccombstr_StrCnv[i] = pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 CW2A printstr(*(pccombstr_StrCnv + i)); printf("%s\n",printstr); //無変換出力 _tprintf(_T("%s\n"),*(pccombstr_StrCnv + i)); } //動的確保変数の解放 delete[] pccombstr_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→CStringA(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換SystemString→CStringA\n")); pcstringa_StrCnv = new CStringA[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue, wch, *sizeReturnValue); pcstringa_StrCnv[i] = pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pcstringa_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringa_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→CStringW(ワイド文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換SystemString→CStringW\n")); pcstringw_StrCnv = new CStringW[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue, wch, *sizeReturnValue); pcstringw_StrCnv[i] = pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //wchar_t出力 wprintf(L"%s\n",pcstringw_StrCnv[i]); } //動的確保変数の解放 delete[] pcstringw_StrCnv; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //・SystemString→string(マルチバイト文字) //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ _tprintf(_T("\n文字列の型変換SystemString→string\n")); pstring_StrCnv = new string[*pnStrArrayElement];//要素数分の大きさ+1を確保 //変換 for(int i = 0; i < *pnStrArrayElement; i++){ pin_ptr<const wchar_t> wch = PtrToStringChars(sysstringOrigin[i]); wcstombs_s(sizeReturnValue, NULL, 0,wch, 0); char* pcStrTemp = new char[*sizeReturnValue]; wcstombs_s(sizeReturnValue, pcStrTemp, *sizeReturnValue, wch, *sizeReturnValue); pstring_StrCnv[i] = pcStrTemp; } //出力 for(int i = 0; i < *pnStrArrayElement; i++){ //char変換出力 printf("%s\n",pstring_StrCnv[i].c_str()); } //動的確保変数の解放 delete[] pstring_StrCnv; </syntaxhighlight> と、こんな感じです。もっと効率の良い変換があったらごめんなさい。動的に必要最小限のメモリを確保させながらの処理だとこんな感じになるよっていう例になっていると思います。プログラムによっては、配列の大きさを固定したっていいわけです。その方がコーディングや変数管理が楽になる場合もあります。この章に関しては以上です。既に準備されている型の変換なんてのは、変換するための関数が準備されているので、比較的簡単な技術になります。全角半角変換や文字コード変換処理を実際に組む方が難しいかもしれません。それもおいおい記述したいと思います。 ※2014/09/21 ここまでで、疲れたから、また暫くオヤスミ。次に気が向くのはいつになるのか、誰も知らない。 =='''文字列文字コード変換'''== 文字コード変換は、標準関数だけでは実現できない変換になっています。自分で変換関数を作るのもありですが、既にきちんと作られた変換ライブラリが無償で配布されています。変換処理自体を作成するには、文字コードの体系の理解やエンコーディングの理解が必要です。そして、それに対応する変換処理を作るわけです。ShiftJIS CP932とUnicode UTF-16はマルチバイトとワイド文字の変換によって実現できますので、UTF-8やEUCあるいはJISといった変換には変換処理の作成が必要になってきます。更に同じUnicodeでもUTF-16やUTF-32ではリトルエンディアン方式、ビッグエンディアン方式さらにはBOM(ByteOrderMark)の付加といった変換を考慮する必要もあります。UTF-16やUTF-32では常に複数Byteで一文字が表現され、その複数バイト塊のメモリアドレスの番地の小さい方から文字コードの上位バイトの情報をいれるビッグエンディアンと番地の小さい方に下位バイトの情報をいれていくリトルエンディアンがあり、その文字コードファイルの先頭2ByteにBOMという符号で、どっちの方式が使われているのかを示すものです。先頭アドレスからFF FE と格納されていればビッグエンディアン、FE FF と格納されていればリトルエンディアンであることを示します。あえてBOMを付与しないで、プログラムがどっちの文字コードが使われているか解析する方法や文書を閲覧する都度、ユーザが選択する方法もあります。UTF-8では、複数バイト使われるときには徐々にバイト数が大きくなる可変長の方式をとっていて、リトルエンディアンとかビッグエンディアンという概念がないため、BOMは不要ですが、付与するパターンもゆるされており、BOMありで統一してテキストを作成している人もいることから無意味なBOM付きファイルも存在します。また、このBOMが原因でファイルの読み取りに失敗してしまうUTF-8採用のプログラムも多いようです。どっちのファイルも読み取れるプログラムを作るのが良いですが、BOMありでは動作しないものと割りきって、BOM付きUTF-8を切り捨てていくプログラム作成者もいるように思います。こうすることでBOM付きUTF-8を撲滅することになっているのかもしれません。自分もUTF-8にはBOMは不要だと感じています。あえてBOMを付けれる出力のサポートも必要だと思うし、読み取れるようにもしときたいものですね。そんなプログラム作ったことないですけど…。 ちなみにVisualStudioのコード編集エディタはデフォルトでは、ShiftJIS CP932が利用されます。変更するには、メニューのファイル(F)-保存オプションの詳細設定のエンコード欄の値を変えることで実現できます。行の終わり欄で改行コードも変更できます。特別にテキストの中で特定の文字コードセットのリテラルを使う必要がある以外は基本はShiftJIS CP932でいいのではないでしょうか?L""リテラルでUnicodeも使えますし。 こういった文字コードの変換は、自分のプログラムだけで動作するのではなく、外部におかれた情報を読み込む、あるいは書き換えるといった動作をする場合に必要になってきます。固定の外部ファイルとのやりとりであれば、変換が発生しないように構築すると必要ないし、変換が必要であっても1種類の変換で済みます。ありとあらゆる場所からテキストを読むこむようなプログラムになると、この文字コード変換を網羅しないと利便性が損なわれる結果になります。文字コードの掃出し処理が間違っていると、文字コード破壊プログラムになってしまう可能性もありますので、自分で変換処理を作って、書き出すプログラムを作るのはかなりの知識を必要とします。実績のある変換処理ライブラリを使った方が安全です。速度改善の必要があるような人は自分で変換処理作りに挑むのもよいのかもしれません。ここでは、既存の変換処理ライブラリを使う方法を示し、時間があれば具体的な変換処理の作成について触れたいと思います。 例によって、全部のサンプルを記事に書き起こすまでに相当な時間がかかると思いますので、すこしづつ進めていくことになると思います。 C++/CLIだとEncodingというライブラリを使うことで変換ができますが、C++以下の範囲で扱う場合はIBM社が作成したオープンソースICU(International Components for Unicode)、GNUプロジェクトによって作られLGPLのICONVというライブラリがあります。ほかにも有志によって作られたフリーソフトnkf.dllというライブラリを使う方法もあります。ここではICUを使った方法について記述します。GNUは自由に使うことのできるUnixとしてのOSであるLinuxの開発プロジェクトで、GNU's Not Unixという意味だそうです。そうすると先頭にまたGNUが出てくるから、それは何の意味?ってなるとまたGNUはGNU's Not Unixって略語だよっていう風になる再帰的な略語です。GNUのGの意味は思考を停止しない限り永遠に再帰されます。LGPL(Lesser General Public License)は簡単に表現するとコンパイルするプログラムの配布には関与しないライセンスですが、ライブラリそのものや、制限に関するライセンスの詳細な意味についてはGNUプロジェクトによる説明で解釈して下さい。 ICUはC++(Cpp)の技術を含むプロジェクトですので、C言語の領域からは外れます。C言語だけで、文字コード変換をやろうとすると、このようなライブラリがないために、もっと基礎的なコード変換技術を身に着ける必要があります。根本的な言語でやる方が敷居が高いというのはアセンブラ含めて、同様の事だと言えると思います。ここではそのような基礎的な技術は紹介しないので、C言語だけで実現する必要がある場合には、ICUプロジェクトのソースを解析するなりして、クラスやC++で登場する構文をを使わない形式で実現できるように挑戦してみると良いです。とても大変なことだと思います。 ICUのWebSite<br /> http://site.icu-project.org/<br /> まずここから最新のソースファイルをダウンロードします。<br /> 執筆時点'14/09ではICU Versionは5.4で、VisualStudio2012を使っている分には、現在のICU4CのソースはCygwinも必要とせずにビルドができます。VisualStudio2010で作られているので、初回のソューションファイルオープンでプロジェクトの変換が必要になります。ビルド後VisualStudioの設定も以下のとおり実施する必要があります。ICUが利用している開発環境よりも新しいものなら楽にビルドできそうです。 *ビルドの手順 :1.環境変数PATHに[icu配置パス]\icu\bin を追加。x64プロジェクトをビルドするときは[icu配置パス]\icu\bin64っすかね。 :2.[icu配置パス]\icu\source\allinone\allinone.sln を開く(プロジェクト変換ダイアログ表示されたらOKで変換する) ::注)icu配置パスを決めてからビルドをしないと駄目です。ビルド時に生成されるファイルで絶対パスで管理されるDATAがあるため、ビルド後に移動させると動かなくなります。 :3.メニューの[ビルド]-[バッチビルド]を選択し、表示されたダイアログで、Win32かx64のプロジェクトを選択してから→[ビルド]で、ひたすら待つ。全部でおそらく15分(Corei7 3610QM 2.3GHz)くらい ::次のプロジェクト設定Win32 or x64をビルドするときには手順1に戻ることになります。 :4.コマンドプロンプトでテストプログラムを動かす。テストコマンドの引数4種類全部確かめるなら以下4つのコマンド全部実行。それか自分の目的のテストだけ実施。あるいはテストはやらないのもひとつの選択肢。 ::*[icu配置パス]\icu\source\allinone\allinone.bat x86 Debug ::*[icu配置パス]\icu\source\allinone\allinone.bat x86 Release ::*[icu配置パス]\icu\source\allinone\allinone.bat x64 Debug ::*[icu配置パス]\icu\source\allinone\allinone.bat x64 Release ソースを見ることができるのですが、とにかく巨大なプロジェクトで、ソースを見るのも勉強になるかもしれません。巨大プロジェクトならではのアイデア満載かなぁと思います。ワーニングもいっぱいだけど、まぁ気にしない。バグもあるみたいで、同時に配布されるテストプログラムをビルド後に動作させてみるのですが、うまく動かない関数もありました。今回の目的にはあまり関係してこない部分のバグだと思うので、このまま使ってみます。 以下、テスト時のエラーログです。ひょっとしたら自分だけなのかもしれませんが、既知のバグみたいな?いやテストだけで出るエラーみたいな感じなので気にしないことにします。え?ホントにそれでいいのか?調べるのも面倒だし、放置。 <syntaxhighlight lang="text"> KNOWN ISSUES #11217 <http://bugs.icu-project.org/trac/ticket/11217> /tsutil/cldrtest/TestExemplarSet "Fix result of uscript_getCode for yi: USCRIPT_YI -> USCRIPT_HEBREW" /tsutil/cldrtest/VerifyTranslation "Fix result of uscript_getCode for yi: USCRIPT_YI -> USCRIPT_HEBREW" (To run suppressed tests, use the -K option.) SUMMARY: ******* [Total error count: 590] Errors in [/tsconv/nucnvtst/TestISO_2022_JP] [/tsconv/nucnvtst/TestJIS] [/tsconv/nucnvtst/TestISO_2022_JP_1] [/tsconv/nucnvtst/TestISO_2022_JP_2] [/tsconv/nucnvtst/TestHZ] [/tsconv/nucnvtst/TestJitterbug2346] [/tsconv/nccbtst/TestSkipCallBack] [/tsconv/nccbtst/TestSubWithValueCallBack] [/tsconv/ncnvtst/TestResetBehaviour] </syntaxhighlight> 表:icucheck.bat Win32 Release のテスト結果でのエラー あらゆる文字コードの変換だけでなく、大文字小文字相互変換、全角半角相互変換、ひらがなカタカナ相互変換、他にもひらがなやカタカナからのローマ字相互変換といった複雑な変換も提供しています。そのほかにも通貨フォーマットや時間表記変換といった面白い変換も組み込まれています。ここでは文字コード変換のみを取り上げます。文字コードをファイルに出力するのはもっとあとで説明する予定なので、ここでは、サンプルとなる文字列をその文字コード体系に合わせて16進数で表現した配列として扱い、それを基に変換後の文字コード配列が生成されるのを確かめます。変換後の文字コードがUNICODEやShiftJIS以外になる場合も同じく16進数で表現される配列で示します、逆に異なる文字コードから基に戻す変換も確認します。 *プロジェクトの設定 :1.Win32プロジェクトなら[icu配置パス]\icu\bin、x64プロジェクトなら[icu配置パス]\icu\bin64という絶対パスを、プロジェクト毎にプロジェクトの設定の中(ALT+F7キーで表示されるダイアログの構成プロパティの中)にあるVCディレクトリの実行可能ファイルディレクトリにパスを設定する。Win32プロジェクトとx64プロジェクトとでパスは異なるためプロジェクト毎に毎回設定した方が良いでしょう。文字コード変換を必要とするプロジェクトを作成する都度、設定しましょう。面倒な人でWin32プロジェクトしか作らないX54しか作らないという人は、どちらかの環境変数PATHに入れてもいいでしょう。でも結局、この次にlibファイルやincludeファイルの設定もしないといけないし、やっぱりプロジェクト毎に設定しましょう。一見、面倒そうだけど、そんなにたくさんプロジェクト作る人ってあんまりいないと思います。小さなサンプルコードプロジェクトをたくさん作って、それで変換テストしまくる人は大変かもしれませんね。自分は基本Win32のプロジェクトで遊んでるので、環境変数PATHにWin32プロジェクト用の実行パスを登録しています。X64をビルドするときに、また切り替えます。このとき、新しいパス変数を作ってPATH32=[icu配置パス]\icu\bin;(他のSDKの実行パス);…;…でPATH64=[icu配置パス]\icu\bin64;(他のSDKの実行パス);…;…として、環境変数PATHにはPATH=(既存パス1);(既存パス2);%PATH32%;(既存パスn)みたいに登録するといろいろなSDKをまとめて切り替えられます。64に変えればいいんだもんね。 :2.Win32プロジェクトなら[icu配置パス]\icu\lib、x64プロジェクトなら[icu配置パス]\icu\lib64という絶対パスをプロジェクト毎にプロジェクトの設定の中にあるVCディレクトリのライブラリディレクトリにパスを設定する。これも実行パス同様に管理して環境変数LIB32とLIB64を作って、環境変数LIB=%LIB32%とかにすると、プロジェクトの設定にはライブラリの欄に$(LIB)と入力するだけでよくなります。 :3.Win32,x64共通ですが、[icu配置パス]\icu\includeをプロジェクト毎にプロジェクトの設定の中にあるVCディレクトリのインクルードディレクトリに設定します。自分はこれも環境変数INCLUDEを作っていて、$(INCLUDE)と設定しています。 :4.デバッグプロジェクトならicuucd.lib、リリースプロジェクトならicuuc.libという追加するべきライブラリ名をプロジェクト毎にプロジェクトの設定の中にあるリンカー-入力の追加の依存ファイル欄に追記します。 このICUはC++/CLIプロジェクトのような/clrオプションコンパイルには対応していません。UConverterという構造体が実態が未定義のまま利用されていますが、このような宣言がされているだけのものをビルドするとリンカーエラーが発生し、プログラムは動作しません。対処方法はあると思いますが、ICUはとてつもなく大きなプロジェクトファイルです。C++/CLIで使っていくには、現在のバージョンを永続的に使っていくのか?メンテしきれるか?どうかも含めた検討が必要になります。 リンカー ツールの警告 LNK4248 http://msdn.microsoft.com/ja-jp/library/h8027ys9.aspx プロジェクトの設定は以上です。以下が実際の変換サンプルになります。これまでのサンプルもそうですが、実際にはサポートクラスを作って、毎回新しく変数定義しているものは、クラスを呼ぶたびにまとめて生成されるようなセットを作るべきです。変換サポートクラスの作り方については、クラスに関する記述を掘り下げるセクションで触れたいと思いますが、ここでは例のごとく直線的なプログラムになっています。 <syntaxhighlight lang="cpp" line start="1"> #include "stdafx.h" #include <unicode/ucnv.h> #include <stdlib.h> #include <string> #include <mbstring.h> #include <iostream> #include <locale> #include <tchar.h> #include "atlstr.h"//CString,CStringA,CStringWおよびLPTSTR,LPWSTR,LPSTR,LPCTSTR,LPCWSTR,LPCSTRの定義プリプロセッサ #include "cstringt.h"//CStringTの定義プリプロセッサ #include "atlbase.h" #include "comutil.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { _tsetlocale(LC_ALL, _T("Japanese")); // "JIS文字列" のJIS(iso-2022-jp)表現↓ string jis = "\x4A\x49\x53\x1B\x24\x42\x4A\x38\x3B\x7A\x4E\x73\x1B\x28\x42"; wstring wstr = L"JIS文字列"; //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // JIS → UNICODE //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ UConverter* ucnvTest; UErrorCode uerrorNum; int nStrSize; int nStrResultSize; nStrSize = jis.size(); std::wstring stringCnvResult(nStrSize, L'\0'); ucnvTest = ucnv_open("iso-2022-jp", &uerrorNum); nStrResultSize = ucnv_toUChars( ucnvTest, &stringCnvResult[0], stringCnvResult.size(), // 変換先のポインタとサイズ &jis[0], nStrSize, // 変換元のポインタとサイズ &uerrorNum ); stringCnvResult.resize(nStrResultSize); ucnv_close(ucnvTest); _tprintf(_T("%s\n"), stringCnvResult.c_str()); wchar_t* pwcStr = new wchar_t[_tcslen(stringCnvResult.c_str()) + 1]; _tcscpy_s(pwcStr,_tcslen(stringCnvResult.c_str()) + 1,stringCnvResult.c_str()); for(int i = 0;i < (int)_tcslen(stringCnvResult.c_str());i++){ printf("%04x:",*(pwcStr + i)); } printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // UNICODE → JIS //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ucnvTest = ucnv_open("iso-2022-jp", &uerrorNum); nStrSize = wstr.size(); std::string stringCnvResult2(ucnv_getMaxCharSize(ucnvTest) * nStrSize , L'\0'); nStrResultSize = ucnv_fromUChars( ucnvTest, &stringCnvResult2[0], stringCnvResult2.size(), // 変換先のポインタとサイズ &wstr[0], nStrSize, // 変換元のポインタとサイズ &uerrorNum ); stringCnvResult2.resize(nStrResultSize); ucnv_close(ucnvTest); _tprintf(_T("%s\n"), stringCnvResult2.c_str()); char* pcStr = new char[strlen(stringCnvResult2.c_str()) + 1]; strcpy_s(pcStr,strlen(stringCnvResult2.c_str()) + 1,stringCnvResult2.c_str()); for(int i = 0;i < (int)strlen(stringCnvResult2.c_str());i++){ printf("%02x:",*(pcStr + i)); } printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // UNICODE → SJIS //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ucnvTest = ucnv_open("shift_jis", &uerrorNum); nStrSize = wstr.size(); std::string stringCnvResult3(ucnv_getMaxCharSize(ucnvTest) * nStrSize , L'\0'); nStrResultSize = ucnv_fromUChars( ucnvTest, &stringCnvResult3[0], stringCnvResult3.size(), // 変換先のポインタとサイズ &wstr[0], nStrSize, // 変換元のポインタとサイズ &uerrorNum ); stringCnvResult3.resize(nStrResultSize); ucnv_close(ucnvTest); printf("%s\n", stringCnvResult3.c_str()); char* pcStr2 = new char[strlen(stringCnvResult3.c_str()) + 1]; strcpy_s(pcStr2,strlen(stringCnvResult3.c_str()) + 1,stringCnvResult3.c_str()); for(int i = 0;i < (int)strlen(stringCnvResult3.c_str());i++){ printf("%02x:",0x000000ff & *(pcStr2 + i)); } printf("\n"); return 0; } </syntaxhighlight> という具合に変換すると結果として <syntaxhighlight lang="text"> JIS文字列 004a:0049:0053:6587:5b57:5217: ????稻獎?B 4a:49:53:1b:24:42:4a:38:3b:7a:4e:73:1b:28:42: JIS文字列 4a:49:53:95:b6:8e:9a:97:f1: </syntaxhighlight> のようなものが得られます。 これですべての変換が出来そうな気分ですが、実際にはshift_jisコード上で展開される携帯電話各社の絵文字があったり、UNICODE上での文字の重複による変換先の最適化、UNICODEにしかない文字の変換があった場合の処理など実際のプログラミング技術が、ここをスタート地点として、広がっています。auとDocomoは絵文字を統一させたんだったかも…ソフトバンクはかなり独自の体系を維持。ウィルコム。イーモバ…ふむ、どうなってるんだろ。んで、UNICODEにも少し絵文字が追加されてたり…。でも結局、それを表示するのはその文字コードのグリフをもったフォントファイルなわけです。やれる範囲。結構、限られてます。特殊文字には、年号とかもあります。次の年号の文字コードとかも、後で変更追加になるに違いない。㍻。←平成を一文字で表した環境依存文字。文字コードの世界が今のようになった歴史を知るのも面白いですし、これからの文字コードはどうあるべきかを議論する国際的なワーキンググループも活動しています。絶賛迷走中あるいは理想形へ向かって進行中です。メールで半角カタカナが使えないのはJISコード iso-2022-jpのおかげです。更にはメールはBase64という変換方式もあり、バイナリーコードや文字列コードを先頭から6ビットずつ4セットにしていくエンコードがあります。こうやってメールはおくられているんだなと感心したものです。http://ja.wikipedia.org/wiki/Base64 上記のサンプルですが、動作しますが、ucnv_openでエラーコードが返ってきています。-122だそうで調べてみるとAMBIGUOUS_ALIAS_WARNING(-122) This converter alias can go to different converter implementations.とのことです。ワーニングレベルと認識できますが、他の方法で実装できるよだって。どういうこと? 対応している変換は以下の文字コードになります。一番左が基本文字セット名で、その横にエイリアス名の個数、★の横にスペース区切りで全エイリアス名(別名)を記載しました。ucnv_open関数などの第一引数にはこのエイリアス名を大文字小文字の区別なく記載することができるようです。 shift_jisは41行目と42行目でダブって登場しますね。ibm-943も。どっちが使われる?調べるの?いやいや、調べきれそうもないです。よくみかけるコード名でいくと上側が使われるべきなんでしょうけど。どっちもそれほど変わらないのか、それとも、これが俗にいうマイクロソフトsjisとsjisの違いなのか?Windowsなら上で、それ以外は純粋なShift_JISってことなのか。AMBIGUOUS_ALIAS_WARNINGの原因にはあいまいな変換がされたことに由来するらしいが、どうも、指定方法の問題ではないらしい。謎は謎のままに。謎というよりはICUの英語を理解できないだけだが…。だからどうしろとは言わない説明書がうらめしい。 ibm-943_P15A-2003 19 ★ibm-943_P15A-2003 ibm-943 '''Shift_JIS''' MS_Kanji csShiftJIS windows-31j csWindows31J x-sjis x-ms-cp932 '''cp932''' windows-93cp943c IBM-943C ms932 pck '''sjis''' ibm-943_VSUB_VPUA x-MS932_0213 x-JISAutoDetect ibm-943_P130-1999 7 ★ibm-943_P130-1999 ibm-943 '''Shift_JIS''' cp943 943 ibm-943_VASCII_VSUB_VPUA x-IBM943 <syntaxhighlight lang="text" line start="1"> UTF-8 14 ★UTF-8 ibm-1208 ibm-1209 ibm-5304 ibm-5305 ibm-13496 ibm-13497 ibm-17592 ibm-17593 windows-65001 cp1208 x-UTF_8J unicode-1-1-utf unicode-2-0-utf-8 UTF-16 7 ★UTF-16 ISO-10646-UCS-2 ibm-1204 ibm-1205 unicode csUnicode ucs-2 UTF-16BE 21 ★UTF-16BE x-utf-16be UnicodeBigUnmarked ibm-1200 ibm-1201 ibm-13488 ibm-13489 ibm-17584 ibm-17585 ibm-21680 ibm-21681 ibm-257 ibm-25777 ibm-29872 ibm-29873 ibm-61955 ibm-61956 windows-1201 cp1200 cp1201 UTF16_BigEndian UTF-16LE 17 ★UTF-16LE x-utf-16le UnicodeLittleUnmarked ibm-1202 ibm-1203 ibm-13490 ibm-13491 ibm-17586 ibm-17587 ibm-21682 ibm-21683 ibm-778 ibm-25779 ibm-29874 ibm-29875 UTF16_LittleEndian windows-1200 UTF-32 6 ★UTF-32 ISO-10646-UCS-4 ibm-1236 ibm-1237 csUCS4 ucs-4 UTF-32BE 5 ★UTF-32BE UTF32_BigEndian ibm-1232 ibm-1233 ibm-9424 UTF-32LE 4 ★UTF-32LE UTF32_LittleEndian ibm-1234 ibm-1235 UTF16_PlatformEndian 1 ★UTF16_PlatformEndian UTF16_OppositeEndian 1 ★UTF16_OppositeEndian UTF32_PlatformEndian 1 ★UTF32_PlatformEndian UTF32_OppositeEndian 1 ★UTF32_OppositeEndian UTF-16BE,version=1 2 ★UTF-16BE,version=1 UnicodeBig UTF-16LE,version=1 3 ★UTF-16LE,version=1 UnicodeLittle x-UTF-16LE-BOM UTF-16,version=1 1 ★UTF-16,version=1 UTF-16,version=2 1 ★UTF-16,version=2 UTF-7 4 ★UTF-7 windows-65000 unicode-1-1-utf-7 unicode-2-0-utf-7 IMAP-mailbox-name 1 ★IMAP-mailbox-name SCSU 3 ★SCSU ibm-1212 ibm-1213 BOCU-1 4 ★BOCU-1 csBOCU-1 ibm-1214 ibm-1215 CESU-8 2 ★CESU-8 ibm-9400 ISO-8859-1 11 ★ISO-8859-1 ibm-819 IBM819 cp819 latin1 8859_1 csISOLatin1 iso-ir-100 ISO_8859-1:1987 l1 819 US-ASCII 16 ★US-ASCII ASCII ANSI_X3.4-1968 ANSI_X3.4-1986 ISO_646.irv:1991 iso_646.irv:1983 ISO646-US us csASCII iso-ir-6 cp367 ascii7 64 windows-20127 ibm-367 IBM367 gb18030 4 ★gb18030 ibm-1392 windows-54936 GB18030 ibm-912_P100-1995 12 ★ibm-912_P100-1995 ibm-912 ISO-8859-2 ISO_8859-2:1987 latin2 csISOLatin2 iso-ir-101 l2 8859_2 cp912 912 windows-2859 ibm-913_P100-2000 12 ★ibm-913_P100-2000 ibm-913 ISO-8859-3 ISO_8859-3:1988 latin3 csISOLatin3 iso-ir-109 l3 8859_3 cp913 913 windows-2859 ibm-914_P100-1995 12 ★ibm-914_P100-1995 ibm-914 ISO-8859-4 latin4 csISOLatin4 iso-ir-110 ISO_8859-4:1988 l4 8859_4 cp914 914 windows-2859 ibm-915_P100-1995 11 ★ibm-915_P100-1995 ibm-915 ISO-8859-5 cyrillic csISOLatinCyrillic iso-ir-144 ISO_8859-5:1988 8859_5 cp915 915 window28595 ibm-1089_P100-1995 16 ★ibm-1089_P100-1995 ibm-1089 ISO-8859-6 arabic csISOLatinArabic iso-ir-127 ISO_8859-6:1987 ECMA-114 ASMO-708 8859_6p1089 1089 windows-28596 ISO-8859-6-I ISO-8859-6-E x-ISO-8859-6S ibm-9005_X110-2007 13 ★ibm-9005_X110-2007 ibm-9005 ISO-8859-7 8859_7 greek greek8 ELOT_928 ECMA-118 csISOLatinGreek iso-ir-126 ISO_8859-7987 windows-28597 sun_eu_greek ibm-813_P100-1995 4 ★ibm-813_P100-1995 ibm-813 cp813 813 ibm-5012_P100-1999 12 ★ibm-5012_P100-1999 ibm-5012 ISO-8859-8 hebrew csISOLatinHebrew iso-ir-138 ISO_8859-8:1988 ISO-8859-8-I ISO-8859-8-8859_8 windows-28598 hebrew8 ibm-916_P100-1995 4 ★ibm-916_P100-1995 ibm-916 cp916 916 ibm-920_P100-1995 15 ★ibm-920_P100-1995 ibm-920 ISO-8859-9 latin5 csISOLatin5 iso-ir-148 ISO_8859-9:1989 l5 8859_9 cp920 920 windows-2859ECMA-128 turkish8 turkish iso-8859_10-1998 7 ★iso-8859_10-1998 ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 iso-8859_11-2001 4 ★iso-8859_11-2001 ISO-8859-11 thai8 x-iso-8859-11 ibm-921_P100-1995 8 ★ibm-921_P100-1995 ibm-921 ISO-8859-13 8859_13 windows-28603 cp921 921 x-IBM921 iso-8859_14-1998 7 ★iso-8859_14-1998 ISO-8859-14 iso-ir-199 ISO_8859-14:1998 latin8 iso-celtic l8 ibm-923_P100-1998 13 ★ibm-923_P100-1998 ibm-923 ISO-8859-15 Latin-9 l9 8859_15 latin0 csisolatin0 csisolatin9 iso8859_15_fdis cp923 923 wdows-28605 ibm-942_P12A-1999 10 ★ibm-942_P12A-1999 ibm-942 ibm-932 cp932 shift_jis78 sjis78 ibm-942_VSUB_VPUA ibm-932_VSUB_VPUA x-IBM942 x-IBM942C ibm-943_P15A-2003 19 ★ibm-943_P15A-2003 ibm-943 Shift_JIS MS_Kanji csShiftJIS windows-31j csWindows31J x-sjis x-ms-cp932 cp932 windows-93cp943c IBM-943C ms932 pck sjis ibm-943_VSUB_VPUA x-MS932_0213 x-JISAutoDetect ibm-943_P130-1999 7 ★ibm-943_P130-1999 ibm-943 Shift_JIS cp943 943 ibm-943_VASCII_VSUB_VPUA x-IBM943 ibm-33722_P12A_P12A-2009_U2 5 ★ibm-33722_P12A_P12A-2009_U2 ibm-33722 ibm-5050 ibm-33722_VPUA IBM-eucJP ibm-33722_P120-1999 9 ★ibm-33722_P120-1999 ibm-33722 ibm-5050 cp33722 33722 ibm-33722_VASCII_VPUA x-IBM33722 x-IBM33722A x-IBM33722C ibm-954_P101-2007 4 ★ibm-954_P101-2007 ibm-954 x-IBM954 x-IBM954C euc-jp-2007 7 ★euc-jp-2007 EUC-JP Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese X-EUC-JP eucjis ujis ibm-1373_P100-2002 3 ★ibm-1373_P100-2002 ibm-1373 windows-950 windows-950-2000 7 ★windows-950-2000 Big5 csBig5 windows-950 x-windows-950 x-big5 ms950 ibm-950_P110-1999 5 ★ibm-950_P110-1999 ibm-950 cp950 950 x-IBM950 ibm-1375_P100-2008 5 ★ibm-1375_P100-2008 ibm-1375 Big5-HKSCS big5hk HKSCS-BIG5 ibm-5471_P100-2006 7 ★ibm-5471_P100-2006 ibm-5471 Big5-HKSCS MS950_HKSCS hkbig5 big5-hkscs:unicode3.0 x-MS950-HKSCS ibm-1386_P100-2001 5 ★ibm-1386_P100-2001 ibm-1386 cp1386 windows-936 ibm-1386_VSUB_VPUA windows-936-2000 5 ★windows-936-2000 GBK CP936 MS936 windows-936 ibm-1383_P110-1999 10 ★ibm-1383_P110-1999 ibm-1383 GB2312 csGB2312 cp1383 1383 EUC-CN ibm-eucCN hp15CN ibm-1383_VPUA ibm-5478_P100-1995 8 ★ibm-5478_P100-1995 ibm-5478 GB_2312-80 chinese iso-ir-58 csISO58GB231280 gb2312-1980 GB2312.1980-0 euc-tw-2014 2 ★euc-tw-2014 EUC-TW ibm-964_P110-1999 8 ★ibm-964_P110-1999 ibm-964 ibm-eucTW cns11643 cp964 964 ibm-964_VPUA x-IBM964 ibm-949_P110-1999 6 ★ibm-949_P110-1999 ibm-949 cp949 949 ibm-949_VASCII_VSUB_VPUA x-IBM949 ibm-949_P11A-1999 6 ★ibm-949_P11A-1999 ibm-949 cp949c ibm-949_VSUB_VPUA x-IBM949C IBM-949C ibm-970_P110_P110-2006_U2 13 ★ibm-970_P110_P110-2006_U2 ibm-970 EUC-KR KS_C_5601-1987 windows-51949 csEUCKR ibm-eucKR KSC_5601 5601 cp97070 ibm-970_VPUA x-IBM970 ibm-971_P100-1995 4 ★ibm-971_P100-1995 ibm-971 ibm-971_VPUA x-IBM971 ibm-1363_P11B-1998 14 ★ibm-1363_P11B-1998 ibm-1363 KS_C_5601-1987 KS_C_5601-1989 KSC_5601 csKSC56011987 korean iso-ir-149 cp1363 5601 kscindows-949 ibm-1363_VSUB_VPUA x-IBM1363C ibm-1363_P110-1997 4 ★ibm-1363_P110-1997 ibm-1363 ibm-1363_VASCII_VSUB_VPUA x-IBM1363 windows-949-2000 10 ★windows-949-2000 windows-949 KS_C_5601-1987 KS_C_5601-1989 KSC_5601 csKSC56011987 korean iso-ir-149 ms949 x-KSC5601 windows-874-2000 5 ★windows-874-2000 TIS-620 windows-874 MS874 x-windows-874 ibm-874_P100-1995 8 ★ibm-874_P100-1995 ibm-874 ibm-9066 cp874 TIS-620 tis620.2533 eucTH x-IBM874 ibm-1162_P100-1999 2 ★ibm-1162_P100-1999 ibm-1162 ibm-437_P100-1995 7 ★ibm-437_P100-1995 ibm-437 IBM437 cp437 437 csPC8CodePage437 windows-437 ibm-720_P100-1997 5 ★ibm-720_P100-1997 ibm-720 windows-720 DOS-720 x-IBM720 ibm-737_P100-1997 7 ★ibm-737_P100-1997 ibm-737 IBM737 cp737 windows-737 737 x-IBM737 ibm-775_P100-1996 7 ★ibm-775_P100-1996 ibm-775 IBM775 cp775 csPC775Baltic windows-775 775 ibm-850_P100-1995 7 ★ibm-850_P100-1995 ibm-850 IBM850 cp850 850 csPC850Multilingual windows-850 ibm-851_P100-1995 6 ★ibm-851_P100-1995 ibm-851 IBM851 cp851 851 csPC851 ibm-852_P100-1995 7 ★ibm-852_P100-1995 ibm-852 IBM852 cp852 852 csPCp852 windows-852 ibm-855_P100-1995 8 ★ibm-855_P100-1995 ibm-855 IBM855 cp855 855 csIBM855 csPCp855 windows-855 ibm-856_P100-1995 6 ★ibm-856_P100-1995 ibm-856 IBM856 cp856 856 x-IBM856 ibm-857_P100-1995 7 ★ibm-857_P100-1995 ibm-857 IBM857 cp857 857 csIBM857 windows-857 ibm-858_P100-1997 8 ★ibm-858_P100-1997 ibm-858 IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro cp858 windows-858 ibm-860_P100-1995 6 ★ibm-860_P100-1995 ibm-860 IBM860 cp860 860 csIBM860 ibm-861_P100-1995 8 ★ibm-861_P100-1995 ibm-861 IBM861 cp861 861 cp-is csIBM861 windows-861 ibm-862_P100-1995 8 ★ibm-862_P100-1995 ibm-862 IBM862 cp862 862 csPC862LatinHebrew DOS-862 windows-862 ibm-863_P100-1995 6 ★ibm-863_P100-1995 ibm-863 IBM863 cp863 863 csIBM863 ibm-864_X110-1999 5 ★ibm-864_X110-1999 ibm-864 IBM864 cp864 csIBM864 ibm-865_P100-1995 6 ★ibm-865_P100-1995 ibm-865 IBM865 cp865 865 csIBM865 ibm-866_P100-1995 7 ★ibm-866_P100-1995 ibm-866 IBM866 cp866 866 csIBM866 windows-866 ibm-867_P100-1998 3 ★ibm-867_P100-1998 ibm-867 x-IBM867 ibm-868_P100-1995 7 ★ibm-868_P100-1995 ibm-868 IBM868 CP868 868 csIBM868 cp-ar ibm-869_P100-1995 8 ★ibm-869_P100-1995 ibm-869 IBM869 cp869 869 cp-gr csIBM869 windows-869 ibm-878_P100-1996 7 ★ibm-878_P100-1996 ibm-878 KOI8-R koi8 csKOI8R windows-20866 cp878 ibm-901_P100-1999 2 ★ibm-901_P100-1999 ibm-901 ibm-902_P100-1999 2 ★ibm-902_P100-1999 ibm-902 ibm-922_P100-1999 6 ★ibm-922_P100-1999 ibm-922 IBM922 cp922 922 x-IBM922 ibm-1168_P100-2002 4 ★ibm-1168_P100-2002 ibm-1168 KOI8-U windows-21866 ibm-4909_P100-1999 2 ★ibm-4909_P100-1999 ibm-4909 ibm-5346_P100-1998 4 ★ibm-5346_P100-1998 ibm-5346 windows-1250 cp1250 ibm-5347_P100-1998 5 ★ibm-5347_P100-1998 ibm-5347 windows-1251 cp1251 ANSI1251 ibm-5348_P100-1997 4 ★ibm-5348_P100-1997 ibm-5348 windows-1252 cp1252 ibm-5349_P100-1998 4 ★ibm-5349_P100-1998 ibm-5349 windows-1253 cp1253 ibm-5350_P100-1998 4 ★ibm-5350_P100-1998 ibm-5350 windows-1254 cp1254 ibm-9447_P100-2002 4 ★ibm-9447_P100-2002 ibm-9447 windows-1255 cp1255 ibm-9448_X100-2005 5 ★ibm-9448_X100-2005 ibm-9448 windows-1256 cp1256 x-windows-1256S ibm-9449_P100-2002 4 ★ibm-9449_P100-2002 ibm-9449 windows-1257 cp1257 ibm-5354_P100-1998 4 ★ibm-5354_P100-1998 ibm-5354 windows-1258 cp1258 ibm-1250_P100-1995 3 ★ibm-1250_P100-1995 ibm-1250 windows-1250 ibm-1251_P100-1995 3 ★ibm-1251_P100-1995 ibm-1251 windows-1251 ibm-1252_P100-2000 3 ★ibm-1252_P100-2000 ibm-1252 windows-1252 ibm-1253_P100-1995 3 ★ibm-1253_P100-1995 ibm-1253 windows-1253 ibm-1254_P100-1995 3 ★ibm-1254_P100-1995 ibm-1254 windows-1254 ibm-1255_P100-1995 2 ★ibm-1255_P100-1995 ibm-1255 ibm-5351_P100-1998 3 ★ibm-5351_P100-1998 ibm-5351 windows-1255 ibm-1256_P110-1997 2 ★ibm-1256_P110-1997 ibm-1256 ibm-5352_P100-1998 3 ★ibm-5352_P100-1998 ibm-5352 windows-1256 ibm-1257_P100-1995 2 ★ibm-1257_P100-1995 ibm-1257 ibm-5353_P100-1998 3 ★ibm-5353_P100-1998 ibm-5353 windows-1257 ibm-1258_P100-1997 3 ★ibm-1258_P100-1997 ibm-1258 windows-1258 macos-0_2-10.2 7 ★macos-0_2-10.2 macintosh mac csMacintosh windows-10000 macroman x-macroman macos-6_2-10.4 5 ★macos-6_2-10.4 x-mac-greek windows-10006 macgr x-MacGreek macos-7_3-10.2 7 ★macos-7_3-10.2 x-mac-cyrillic windows-10007 mac-cyrillic maccy x-MacCyrillic x-MacUkraine macos-29-10.2 7 ★macos-29-10.2 x-mac-centraleurroman windows-10029 x-mac-ce macce maccentraleurope x-MacCentralEurope macos-35-10.2 5 ★macos-35-10.2 x-mac-turkish windows-10081 mactr x-MacTurkish ibm-1051_P100-1995 7 ★ibm-1051_P100-1995 ibm-1051 hp-roman8 roman8 r8 csHPRoman8 x-roman8 ibm-1276_P100-1995 4 ★ibm-1276_P100-1995 ibm-1276 Adobe-Standard-Encoding csAdobeStandardEncoding ibm-1006_P100-1995 6 ★ibm-1006_P100-1995 ibm-1006 IBM1006 cp1006 1006 x-IBM1006 ibm-1098_P100-1995 6 ★ibm-1098_P100-1995 ibm-1098 IBM1098 cp1098 1098 x-IBM1098 ibm-1124_P100-1996 5 ★ibm-1124_P100-1996 ibm-1124 cp1124 1124 x-IBM1124 ibm-1125_P100-1997 3 ★ibm-1125_P100-1997 ibm-1125 cp1125 ibm-1129_P100-1997 2 ★ibm-1129_P100-1997 ibm-1129 ibm-1131_P100-1997 3 ★ibm-1131_P100-1997 ibm-1131 cp1131 ibm-1133_P100-1997 2 ★ibm-1133_P100-1997 ibm-1133 ISO_2022,locale=ja,version=0 5 ★ISO_2022,locale=ja,version=0 ISO-2022-JP csISO2022JP x-windows-iso2022jp x-windows-50220 ISO_2022,locale=ja,version=1 7 ★ISO_2022,locale=ja,version=1 ISO-2022-JP-1 JIS_Encoding csJISEncoding ibm-5054 JIS x-windows-50221 ISO_2022,locale=ja,version=2 3 ★ISO_2022,locale=ja,version=2 ISO-2022-JP-2 csISO2022JP2 ISO_2022,locale=ja,version=3 2 ★ISO_2022,locale=ja,version=3 JIS7 ISO_2022,locale=ja,version=4 2 ★ISO_2022,locale=ja,version=4 JIS8 ISO_2022,locale=ko,version=0 3 ★ISO_2022,locale=ko,version=0 ISO-2022-KR csISO2022KR ISO_2022,locale=ko,version=1 2 ★ISO_2022,locale=ko,version=1 ibm-25546 ISO_2022,locale=zh,version=0 4 ★ISO_2022,locale=zh,version=0 ISO-2022-CN csISO2022CN x-ISO-2022-CN-GB ISO_2022,locale=zh,version=1 2 ★ISO_2022,locale=zh,version=1 ISO-2022-CN-EXT ISO_2022,locale=zh,version=2 3 ★ISO_2022,locale=zh,version=2 ISO-2022-CN-CNS x-ISO-2022-CN-CNS HZ 2 ★HZ HZ-GB-2312 x11-compound-text 3 ★x11-compound-text COMPOUND_TEXT x-compound-text ISCII,version=0 6 ★ISCII,version=0 x-ISCII91 x-iscii-de windows-57002 iscii-dev ibm-4902 ISCII,version=1 6 ★ISCII,version=1 x-iscii-be windows-57003 iscii-bng windows-57006 x-iscii-as ISCII,version=2 4 ★ISCII,version=2 x-iscii-pa windows-57011 iscii-gur ISCII,version=3 4 ★ISCII,version=3 x-iscii-gu windows-57010 iscii-guj ISCII,version=4 4 ★ISCII,version=4 x-iscii-or windows-57007 iscii-ori ISCII,version=5 4 ★ISCII,version=5 x-iscii-ta windows-57004 iscii-tml ISCII,version=6 4 ★ISCII,version=6 x-iscii-te windows-57005 iscii-tlg ISCII,version=7 4 ★ISCII,version=7 x-iscii-ka windows-57008 iscii-knd ISCII,version=8 4 ★ISCII,version=8 x-iscii-ma windows-57009 iscii-mlm LMBCS-1 3 ★LMBCS-1 lmbcs ibm-65025 ibm-37_P100-1995 13 ★ibm-37_P100-1995 ibm-37 IBM037 ibm-037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl csIBM037 cp037 037 cpibm3cp37 ibm-273_P100-1995 7 ★ibm-273_P100-1995 ibm-273 IBM273 CP273 csIBM273 ebcdic-de 273 ibm-277_P100-1995 9 ★ibm-277_P100-1995 ibm-277 IBM277 cp277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 ebcdic-dk 277 ibm-278_P100-1995 9 ★ibm-278_P100-1995 ibm-278 IBM278 cp278 ebcdic-cp-fi ebcdic-cp-se csIBM278 ebcdic-sv 278 ibm-280_P100-1995 7 ★ibm-280_P100-1995 ibm-280 IBM280 CP280 ebcdic-cp-it csIBM280 280 ibm-284_P100-1995 8 ★ibm-284_P100-1995 ibm-284 IBM284 CP284 ebcdic-cp-es csIBM284 cpibm284 284 ibm-285_P100-1995 9 ★ibm-285_P100-1995 ibm-285 IBM285 CP285 ebcdic-cp-gb csIBM285 cpibm285 ebcdic-gb 285 ibm-290_P100-1995 6 ★ibm-290_P100-1995 ibm-290 IBM290 cp290 EBCDIC-JP-kana csIBM290 ibm-297_P100-1995 8 ★ibm-297_P100-1995 ibm-297 IBM297 cp297 ebcdic-cp-fr csIBM297 cpibm297 297 ibm-420_X120-1999 7 ★ibm-420_X120-1999 ibm-420 IBM420 cp420 ebcdic-cp-ar1 csIBM420 420 ibm-424_P100-1995 7 ★ibm-424_P100-1995 ibm-424 IBM424 cp424 ebcdic-cp-he csIBM424 424 ibm-500_P100-1995 8 ★ibm-500_P100-1995 ibm-500 IBM500 CP500 ebcdic-cp-be csIBM500 ebcdic-cp-ch 500 ibm-803_P100-1999 3 ★ibm-803_P100-1999 ibm-803 cp803 ibm-838_P100-1995 8 ★ibm-838_P100-1995 ibm-838 IBM838 IBM-Thai csIBMThai cp838 838 ibm-9030 ibm-870_P100-1995 7 ★ibm-870_P100-1995 ibm-870 IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 ibm-871_P100-1995 8 ★ibm-871_P100-1995 ibm-871 IBM871 ebcdic-cp-is csIBM871 CP871 ebcdic-is 871 ibm-875_P100-1995 6 ★ibm-875_P100-1995 ibm-875 IBM875 cp875 875 x-IBM875 ibm-918_P100-1995 6 ★ibm-918_P100-1995 ibm-918 IBM918 CP918 ebcdic-cp-ar2 csIBM918 ibm-930_P120-1999 8 ★ibm-930_P120-1999 ibm-930 ibm-5026 IBM930 cp930 930 x-IBM930 x-IBM930A ibm-933_P110-1995 5 ★ibm-933_P110-1995 ibm-933 cp933 933 x-IBM933 ibm-935_P110-1999 5 ★ibm-935_P110-1999 ibm-935 cp935 935 x-IBM935 ibm-937_P110-1999 5 ★ibm-937_P110-1999 ibm-937 cp937 937 x-IBM937 ibm-939_P120-1999 9 ★ibm-939_P120-1999 ibm-939 ibm-931 ibm-5035 IBM939 cp939 939 x-IBM939 x-IBM939A ibm-1025_P100-1995 5 ★ibm-1025_P100-1995 ibm-1025 cp1025 1025 x-IBM1025 ibm-1026_P100-1995 6 ★ibm-1026_P100-1995 ibm-1026 IBM1026 CP1026 csIBM1026 1026 ibm-1047_P100-1995 5 ★ibm-1047_P100-1995 ibm-1047 IBM1047 cp1047 1047 ibm-1097_P100-1995 5 ★ibm-1097_P100-1995 ibm-1097 cp1097 1097 x-IBM1097 ibm-1112_P100-1995 5 ★ibm-1112_P100-1995 ibm-1112 cp1112 1112 x-IBM1112 ibm-1122_P100-1999 5 ★ibm-1122_P100-1999 ibm-1122 cp1122 1122 x-IBM1122 ibm-1123_P100-1995 5 ★ibm-1123_P100-1995 ibm-1123 cp1123 1123 x-IBM1123 ibm-1130_P100-1997 2 ★ibm-1130_P100-1997 ibm-1130 ibm-1132_P100-1998 2 ★ibm-1132_P100-1998 ibm-1132 ibm-1137_P100-1999 2 ★ibm-1137_P100-1999 ibm-1137 ibm-4517_P100-2005 2 ★ibm-4517_P100-2005 ibm-4517 ibm-1140_P100-1997 7 ★ibm-1140_P100-1997 ibm-1140 IBM01140 CCSID01140 CP01140 cp1140 ebcdic-us-37+euro ibm-1141_P100-1997 7 ★ibm-1141_P100-1997 ibm-1141 IBM01141 CCSID01141 CP01141 cp1141 ebcdic-de-273+euro ibm-1142_P100-1997 8 ★ibm-1142_P100-1997 ibm-1142 IBM01142 CCSID01142 CP01142 cp1142 ebcdic-dk-277+euro ebcdic-no-277+euro ibm-1143_P100-1997 8 ★ibm-1143_P100-1997 ibm-1143 IBM01143 CCSID01143 CP01143 cp1143 ebcdic-fi-278+euro ebcdic-se-278+euro ibm-1144_P100-1997 7 ★ibm-1144_P100-1997 ibm-1144 IBM01144 CCSID01144 CP01144 cp1144 ebcdic-it-280+euro ibm-1145_P100-1997 7 ★ibm-1145_P100-1997 ibm-1145 IBM01145 CCSID01145 CP01145 cp1145 ebcdic-es-284+euro ibm-1146_P100-1997 7 ★ibm-1146_P100-1997 ibm-1146 IBM01146 CCSID01146 CP01146 cp1146 ebcdic-gb-285+euro ibm-1147_P100-1997 7 ★ibm-1147_P100-1997 ibm-1147 IBM01147 CCSID01147 CP01147 cp1147 ebcdic-fr-297+euro ibm-1148_P100-1997 7 ★ibm-1148_P100-1997 ibm-1148 IBM01148 CCSID01148 CP01148 cp1148 ebcdic-international-500+euro ibm-1149_P100-1997 7 ★ibm-1149_P100-1997 ibm-1149 IBM01149 CCSID01149 CP01149 cp1149 ebcdic-is-871+euro ibm-1153_P100-1999 4 ★ibm-1153_P100-1999 ibm-1153 IBM1153 x-IBM1153 ibm-1154_P100-1999 2 ★ibm-1154_P100-1999 ibm-1154 ibm-1155_P100-1999 2 ★ibm-1155_P100-1999 ibm-1155 ibm-1156_P100-1999 2 ★ibm-1156_P100-1999 ibm-1156 ibm-1157_P100-1999 2 ★ibm-1157_P100-1999 ibm-1157 ibm-1158_P100-1999 2 ★ibm-1158_P100-1999 ibm-1158 ibm-1160_P100-1999 2 ★ibm-1160_P100-1999 ibm-1160 ibm-1164_P100-1999 2 ★ibm-1164_P100-1999 ibm-1164 ibm-1364_P110-2007 3 ★ibm-1364_P110-2007 ibm-1364 x-IBM1364 ibm-1371_P100-1999 3 ★ibm-1371_P100-1999 ibm-1371 x-IBM1371 ibm-1388_P103-2001 4 ★ibm-1388_P103-2001 ibm-1388 ibm-9580 x-IBM1388 ibm-1390_P110-2003 3 ★ibm-1390_P110-2003 ibm-1390 x-IBM1390 ibm-1399_P110-2003 3 ★ibm-1399_P110-2003 ibm-1399 x-IBM1399 ibm-5123_P100-1999 2 ★ibm-5123_P100-1999 ibm-5123 ibm-8482_P100-1999 2 ★ibm-8482_P100-1999 ibm-8482 ibm-16684_P110-2003 3 ★ibm-16684_P110-2003 ibm-16684 ibm-20780 ibm-4899_P100-1998 2 ★ibm-4899_P100-1998 ibm-4899 ibm-4971_P100-1999 2 ★ibm-4971_P100-1999 ibm-4971 ibm-9067_X100-2005 2 ★ibm-9067_X100-2005 ibm-9067 ibm-12712_P100-1998 3 ★ibm-12712_P100-1998 ibm-12712 ebcdic-he ibm-16804_X110-1999 3 ★ibm-16804_X110-1999 ibm-16804 ebcdic-ar ibm-37_P100-1995,swaplfnl 2 ★ibm-37_P100-1995,swaplfnl ibm-37-s390 ibm-1047_P100-1995,swaplfnl 3 ★ibm-1047_P100-1995,swaplfnl ibm-1047-s390 IBM1047_LF ibm-1140_P100-1997,swaplfnl 2 ★ibm-1140_P100-1997,swaplfnl ibm-1140-s390 ibm-1141_P100-1997,swaplfnl 3 ★ibm-1141_P100-1997,swaplfnl ibm-1141-s390 IBM1141_LF ibm-1142_P100-1997,swaplfnl 2 ★ibm-1142_P100-1997,swaplfnl ibm-1142-s390 ibm-1143_P100-1997,swaplfnl 2 ★ibm-1143_P100-1997,swaplfnl ibm-1143-s390 ibm-1144_P100-1997,swaplfnl 2 ★ibm-1144_P100-1997,swaplfnl ibm-1144-s390 ibm-1145_P100-1997,swaplfnl 2 ★ibm-1145_P100-1997,swaplfnl ibm-1145-s390 ibm-1146_P100-1997,swaplfnl 2 ★ibm-1146_P100-1997,swaplfnl ibm-1146-s390 ibm-1147_P100-1997,swaplfnl 2 ★ibm-1147_P100-1997,swaplfnl ibm-1147-s390 ibm-1148_P100-1997,swaplfnl 2 ★ibm-1148_P100-1997,swaplfnl ibm-1148-s390 ibm-1149_P100-1997,swaplfnl 2 ★ibm-1149_P100-1997,swaplfnl ibm-1149-s390 ibm-1153_P100-1999,swaplfnl 2 ★ibm-1153_P100-1999,swaplfnl ibm-1153-s390 ibm-12712_P100-1998,swaplfnl 2 ★ibm-12712_P100-1998,swaplfnl ibm-12712-s390 ibm-16804_X110-1999,swaplfnl 2 ★ibm-16804_X110-1999,swaplfnl ibm-16804-s390 ebcdic-xml-us 1 ★ebcdic-xml-us </syntaxhighlight> ICU4Cを使ったプログラムをリリースするときは必要なDLLも一緒にexeファイルと同じディレクトリに置いて配布する必要があります。Win32プロジェクトなら[ICU配置パス]\icu\bin\icuuc**.dllが必要になります。x64プロジェクトなら[ICU配置パス]\icu\bin64\icuuc**.dllが必要になります。プロジェクト設定によりbin or bin64\追加libファイル名+バージョン番号.dllという具合にライブラリと対になってると思っていいです。できれば配布する前に開発環境が導入されていない通常のPCで動作チェックするのがよいです。環境が準備できないなら誰かに人柱になってもらって、確認がとれてから正式リリースとか、そういう風にした方がよいです。自分は以前に配布するべきファイルセットを間違えて、迷惑をかけたことがありますので、チェックするようにしています。 =='''文字列大文字小文字変換'''== これは、まぁ関数がありますので簡単に実現できます。 aBcdEfgに書かれているものをABCDEFGに変換したり、あるいはabcdifgに変換したりできます。AbCDeFGみたいに入れ替えたり、英語の自然表記のため文章の始めの文字を探したり、略語や固有名詞の先頭文字を大文字にし、そのほかを小文字にするのはまた別の話になります。入れ替えくらいなら機械的な操作なのでやれると思います。大文字と小文字を同一視する必要のある検索の一致や大文字と小文字を区別しないメールアドレスやドメイン名の文字列変換に利用することもあります。この変換にも先述したICUを利用することができますが、この程度であれば標準関数を利用した方がよいです。DLLファイルを配ったり、プロジェクトにLibライブラリを読み込んだりINCLUDEファイルを設定したり、大きな実行ファイル群を要することになります。どうせ配布するならICUを使った方がよかったりする場合もありますので、ケースバイケースでしょうか? とりあえずは、ICUの方の変換を記載しておきます。大文字、小文字変換の他に日本語ひらがなとカタカナとローマ字の相互変換についてもサンプルを示しました。ICUを使えば、簡単に変換してくれます。完璧ではなさそうなので、一括変換する場合は注意して使う必要はありそうです。 <syntaxhighlight lang="cpp" line start="1"> #pragma once #include "stdafx.h" #include <stdlib.h> #include <string> //std::string型定義 #include <mbstring.h> //mbs***関数 #include <iostream> //cpp cout etc 一般入出力関数 #include <locale> //Locale関数 #include <tchar.h> //TCHAR型+_tcs***関数 #include "atlstr.h" //CString,CStringA,CStringWおよびLPTSTR,LPWSTR,LPSTR,LPCTSTR,LPCWSTR,LPCSTRの定義プリプロセッサ #include "atlbase.h" //同上 #include "cstringt.h" //CStringTの定義プリプロセッサ //_bstr_t型を利用するプリプロセッサ #include "comutil.h" #ifdef _DEBUG #pragma comment(lib, "comsuppwd.lib") #else #pragma comment(lib, "comsuppw.lib") #endif //_bstr_t //ICU ucnvプリプロセッサ #include <unicode/ucnv.h> #include <unicode/translit.h> #ifdef _DEBUG //#pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib")//ICU Transliterate関数を使うために必要なライブラリ 正規表現関数も #pragma comment(lib, "icuucd.lib")//ICU ucnvを使うために必要なライブラリ //#pragma comment(lib, "icuiod.lib") #else //#pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib") #pragma comment(lib, "icuuc.lib") //#pragma comment(lib, "icuio.lib") #endif using namespace std; { _tsetlocale(LC_ALL, _T("Japanese")); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 全角 → 半角変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ UErrorCode errorNum = U_ZERO_ERROR; int nStrSize; //変換元となる全角リテラル std::wstring wstringResult = L"あいうえおアイウエオABCDE@;:*+/"; UnicodeString str(wstringResult.c_str());//変換関数にはUnicodeString型を使うので初期値関数を使って初期化。strは変更可能な変数である必要がある。ココでconstは駄目。 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 半角 → 全角変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"あいうえおアイウエオABCDE@;:*+/"; Transliterator *myTrans = myTrans->createInstance(L"Halfwidth-Fullwidth", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); printf("★半角 → 全角変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 小文字 → 大文字変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"AbcDefGhiJKlmloPQRsTUvWxYzabcDeFgHiJkLmNoPQRstuvwxyZ"; //delete[] myTrans; myTrans = myTrans->createInstance(L"lt-Upper", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); printf("★小文字 → 大文字変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 大文字 → 小文字変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"AbcDefGhiJKlmloPQRsTUvWxYzabcDeFgHiJkLmNoPQRstuvwxyZ"; //delete[] myTrans; myTrans = myTrans->createInstance(L"lt-Lower", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); printf("★大文字 → 小文字変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // カタカナ → ひらがな変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"あいうえおアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★カタカナ → ひらがな\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Katakana-Hiragana", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ひらがな → カタカナ変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"あいうえおぎゃぎゅぎょアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★ひらがな → カタカナ\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Hiragana-Katakana", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ひらがな → カタカナ→半角変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"あいうえおぎゃぎゅぎょアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★ひらがな → カタカナ→半角変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Hiragana-Katakana", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); myTrans = myTrans->createInstance(L"Fullwidth-Halfwidth", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ひらがな → ローマ字変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"あいうえおぎゃぎゅぎょアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★ひらがな → ローマ字変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Hiragana-Latin", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // カタカナ → ローマ字変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"あいうえおアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★カタカナ → ローマ字変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Katakana-Latin", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ローマ字 → ひらがな変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"aiueogyagyugyochachuchepyapyupyovuzazishikemeアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★ローマ字 → ひらがな変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Latin-Hiragana", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ローマ字 → カタカナ変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"aiueogyagyugyochachuchepyapyupyovuzazishikemeアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★ローマ字 → カタカナ変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Latin-Katakana", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ローマ字 → カタカナ→半角変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ str = L"aiueogyagyugyochachuchepyapyupyovuzazishikemeアイウエオギャギュギョアイウエオABCDE@;:*+/"; //delete[] myTrans; printf("★ローマ字 → カタカナ→半角変換\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); myTrans = myTrans->createInstance(L"Latin-Katakana", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); myTrans = myTrans->createInstance(L"Fullwidth-Halfwidth", UTRANS_FORWARD, errorNum); myTrans->transliterate(str); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); } </syntaxhighlight> 出力結果 <syntaxhighlight lang="text"> ★小文字 → 大文字変換 ABCDEFGHIJKLMLOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ: ★大文字 → 小文字変換 abcdefghijklmlopqrstuvwxyzabcdefghijklmnopqrstuvwxyz: ★カタカナ → ひらがな あいうえおアイウエオギャギュギョアイウエオABCDE@;:*+/: あいうえおあいうえおぎゃぎゅぎょあいうえおABCDE@;:*+/: ★ひらがな → カタカナ あいうえおぎゃぎゅぎょアイウエオギャギュギョアイウエオABCDE@;:*+/: アイウエオギャギュギョアイウエオギャギュギョアイウエオABCDE@;:*+/: ★ひらがな → カタカナ→半角変換 あいうえおぎゃぎゅぎょアイウエオギャギュギョアイウエオABCDE@;:*+/: アイウエオギャギュギョアイウエオギャギュギョアイウエオABCDE@;:*+/: ★ひらがな → ローマ字変換 あいうえおぎゃぎゅぎょアイウエオギャギュギョアイウエオABCDE@;:*+/: aiueogyagyugyoアイウエオg~ャg~ュg~ョアイウエオABCDE@;:*+/: ★カタカナ → ローマ字変換 あいうえおアイウエオギャギュギョアイウエオABCDE@;:*+/: あいうえおaiueogyagyugyoaiueoABCDE@;:*+/: ★ひらがな → ひらがな変換 aiueogyagyugyochachuchepyapyupyovuzazishikemeアイウエオギャギュギョアイウエオABCDE@;:*+/: あいうえおぎゃぎゅぎょちゃちゅちぇぴゃぴゅぴょヴざぜぃしけめアイウエオギャギュギョアイウエオあぶくで@;:*+/: ★ひらがな → カタカナ変換 aiueogyagyugyochachuchepyapyupyovuzazishikemeアイウエオギャギュギョアイウエオABCDE@;:*+/: アイウエオギャギュギョチャチュチェピャピュピョヴザゼィシケメアイウエオギャギュギョアイウエオアブクデ@;:*+/: ★ひらがな → カタカナ→半角変換 aiueogyagyugyochachuchepyapyupyovuzazishikemeアイウエオギャギュギョアイウエオABCDE@;:*+/: アイウエオギャギュギョチャチュチェピャピュピョヴザゼィシケメアイウエオギャギュギョアイウエオアブクデ@;:*+/: </syntaxhighlight> ひらがな→ローマ字変換が残念な結果になっているようでして、ひらがなと一緒に記述していたカタカナのギャギュギョをg~ャg~ュg~ョと変換してしまったようです。こんな変換をプログラムで提供することは稀れだと思いますが、ICUのバグのようですので、注意して使いましょう。ひらがなローマ字変換とか変換遊びの範囲まで来てるような気がします。やってみようとするところは凄いと思います。ほかにもたくさんの変換マップがあるようです。テキストエディタで特殊な変換を提供してみるのもおもしろいのかもしれません。使いこなせるユーザの方が少なさそうです。半角全角変換も同じような要領で実施できます。これらの変換は基本的にはUnicodeの中で実施され、その後、Unicodeから違う文字コードへの変換をするといった作業にで文字コードへの対応を実現します。次の項目では、これらの変換と同時に文字コードの変換を行う手法についても触れています。 =='''文字列半角文字全角文字変換'''== これは、標準関数では対応できませんが、ABCD…UVWXYZ@…abc…xyzをABCD…UVWXYZ@…abc…xyzに変換するような作業です。文字コードによっても求める結果や操作が違うので、ICUを使うのが手っ取り早いでしょう。自分で作成できる範囲の変換処理でもあります。 以下はICUを利用した全角→半角変換です。 <syntaxhighlight lang="cpp" line start="1"> #pragma once #include "stdafx.h" #include <stdlib.h> #include <string> //std::string型定義 #include <mbstring.h> //mbs***関数 #include <iostream> //cpp cout etc 一般入出力関数 #include <locale> //Locale関数 #include <tchar.h> //TCHAR型+_tcs***関数 #include "atlstr.h" //CString,CStringA,CStringWおよびLPTSTR,LPWSTR,LPSTR,LPCTSTR,LPCWSTR,LPCSTRの定義プリプロセッサ #include "atlbase.h" //同上 #include "cstringt.h" //CStringTの定義プリプロセッサ //_bstr_t型を利用するプリプロセッサ #include "comutil.h" #ifdef _DEBUG #pragma comment(lib, "comsuppwd.lib") #else #pragma comment(lib, "comsuppw.lib") #endif //_bstr_t //ICU ucnvプリプロセッサ #include <unicode/ucnv.h> #include <unicode/translit.h> #ifdef _DEBUG //#pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib")//ICU Transliterate関数を使うために必要なライブラリ 正規表現関数も #pragma comment(lib, "icuucd.lib")//ICU ucnvを使うために必要なライブラリ //#pragma comment(lib, "icuiod.lib") #else #pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib") #pragma comment(lib, "icuuc.lib") #pragma comment(lib, "icuio.lib") #endif using namespace std; int _tmain(int argc, _TCHAR* argv[]) { _tsetlocale(LC_ALL, _T("Japanese")); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 全角 → 半角変換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ UConverter* ucnv; UErrorCode errorNum = U_ZERO_ERROR; int nStrSize; //変換元となる全角リテラル std::wstring wstringResult = L"あいうえおアイウエオABCDE@;:*+/"; UnicodeString str(wstringResult.c_str());//変換関数にはUnicodeString型を使うので初期値関数を使って初期化。strは変更可能な変数である必要がある。ココでconstは駄目。 //正しい変換結果確認用のリテラル std::wstring wstringResult2 = L"あいうえおアイウエオABCDE@;:*+/"; //変換処理の核となる部分 //変換タイプリテラル const UnicodeString convert_type(L"Fullwidth-Halfwidth"); Transliterator *myTrans = myTrans->createInstance(convert_type, UTRANS_FORWARD, errorNum);//変換方法を設定 myTrans->transliterate(str);//変換 ucnv = ucnv_open("shift_jis", &errorNum); std::string stringResult(str.length() * ucnv_getMaxCharSize(ucnv),'\0');//shift_jisの最大文字サイズと文字数で仮のメモリ確保 ucnv_close(ucnv); //UnicodeStringクラスを使った変換例。Unicode→任意の文字コード。 //但しchar型へしか格納できない変数なのでUnicode→Unicodeのような無意味な変換には適さない。やれるけど… nStrSize = str.extract(0, str.length(), &stringResult[0], "shift_jis");//stringResultにShift_JISに変換した内容を保管。 stringResult.resize(nStrSize);//変換によって判明したメモリサイズに再設定 //UnicodeStringのwchar_w型文字列を格納している先頭アドレスを取得できるメンバ関数。 printf("★UnicodeString変数の出力サンプル\n"); wprintf(L"%s:\n",str.getTerminatedBuffer()); printf("\n"); //★半角変換+shift_jis変換のバイトコード表示にためにchar型へ代入して出力 printf("★半角変換+shift_jis変換\n"); char* pcStr2 = new char[strlen(stringResult.c_str()) + 1]; strcpy_s(pcStr2,strlen(stringResult.c_str()) + 1,stringResult.c_str()); printf("%s %d:\n",stringResult.c_str(),strlen(stringResult.c_str()) + 1); for(int i = 0;i < (int)strlen(stringResult.c_str()) + 1;i++){ printf("%02x:",0x000000FF & *(pcStr2 + i)); } printf("\n"); printf("\n"); //★無変換のバイトコード表示にためにw_char型へ代入して出力 printf("★全角無変換\n"); wchar_t* pcStr = new wchar_t[wcslen(wstringResult.c_str()) + 1]; wcscpy_s(pcStr,wcslen(wstringResult.c_str()) + 1,wstringResult.c_str()); wprintf(L"%s %d:\n",wstringResult.c_str(),wcslen(wstringResult.c_str()) + 1); for(int i = 0;i < (int)wcslen(wstringResult.c_str()) + 1;i++){ printf("%02x:",0x0000FFFF & *(pcStr + i)); } printf("\n"); printf("\n"); //★変換後確認用の手動変換リテラルのバイトコード表示にためにw_char型へ代入して出力 printf("★手動変換(確認用)\n"); wchar_t* pcStr3 = new wchar_t[wcslen(wstringResult2.c_str()) + 1]; wcscpy_s(pcStr3,wcslen(wstringResult2.c_str()) + 1,wstringResult2.c_str()); wprintf(L"%s %d:\n",wstringResult2.c_str(),wcslen(wstringResult2.c_str()) + 1); for(int i = 0;i < (int)wcslen(wstringResult2.c_str()) + 1;i++){ printf("%02x:",0x0000FFFF & *(pcStr3 + i)); } printf("\n"); printf("\n"); //★変換処理をしたUnicodeのバイトコード表示にためにw_char型へ代入して出力 printf("★半角変換Unicode版\n"); wchar_t* pcStr4 = new wchar_t[wcslen(str.getTerminatedBuffer()) + 1]; wcscpy_s(pcStr4,wcslen(str.getTerminatedBuffer()) + 1,str.getTerminatedBuffer()); wprintf(L"%s %d:\n",str.getTerminatedBuffer(),wcslen(str.getTerminatedBuffer()) + 1); for(int i = 0;i < (int)wcslen(str.getTerminatedBuffer()) + 1;i++){ printf("%02x:",0x0000FFFF & *(pcStr4 + i)); } printf("\n"); printf("\n"); retuen 0; } </syntaxhighlight> 出力結果 <syntaxhighlight lang="text"> ★UnicodeString変数の出力サンプル あいうえおアイウエオABCDE@;:*+/: ★半角変換+shift_jis変換 あいうえおアイウエオABCDE@;:*+/ 27: 82:a0:82:a2:82:a4:82:a6:82:a8:b1:b2:b3:b4:b5:41:42:43:44:45:40:3b:3a:2a:2b:2f:00: ★全角無変換 あいうえおアイウエオABCDE@;:*+/ 22: 3042:3044:3046:3048:304a:30a2:30a4:30a6:30a8:30aa:ff21:ff22:ff23:ff24:ff25:ff20:ff1b:ff1a:ff0a:ff0b:ff0f:0000: ★手動変換(確認用) あいうえおアイウエオABCDE@;:*+/ 22: 3042:3044:3046:3048:304a:ff71:ff72:ff73:ff74:ff75:0041:0042:0043:0044:0045:0040:003b:003a:002a:002b:002f:0000: ★半角変換Unicode版 あいうえおアイウエオABCDE@;:*+/ 22: 3042:3044:3046:3048:304a:ff71:ff72:ff73:ff74:ff75:0041:0042:0043:0044:0045:0040:003b:003a:002a:002b:002f:0000: </syntaxhighlight> という感じに変換ができます。ICUの使い方さえわかれば、いろいろできますね。記事を書きながら、自分もようやくわかってきた感じ。ぉぃ。 サンプルプログラムのコメントを読んでいただければ、理解できると思います。逆の変換はconverttypeを書き換えるだけです。 createInstanceで指定できる変換タイプ名は以下のとおりです。 <syntaxhighlight lang="text"> Arabic-Latin Arabic-Latin/BGN Armenian-Latin Armenian-Latin/BGN Azerbaijani-Latin/BGN Belarusian-Latin/BGN Bengali-Devanagari Bengali-Gujarati Bengali-Gurmukhi Bengali-Kannada Bengali-Latin Bengali-Malayalam Bengali-Oriya Bengali-Tamil Bengali-Telugu Bopomofo-Latin Bulgarian-Latin/BGN Cyrillic-Latin Devanagari-Bengali Devanagari-Gujarati Devanagari-Gurmukhi Devanagari-Kannada Devanagari-Latin Devanagari-Malayalam Devanagari-Oriya Devanagari-Tamil Devanagari-Telugu Digit-Tone Fullwidth-Halfwidth Georgian-Latin Georgian-Latin/BGN Greek-Latin Greek-Latin/BGN Greek-Latin/UNGEGN Gujarati-Bengali Gujarati-Devanagari Gujarati-Gurmukhi Gujarati-Kannada Gujarati-Latin Gujarati-Malayalam Gujarati-Oriya Gujarati-Tamil Gujarati-Telugu Gurmukhi-Bengali Gurmukhi-Devanagari Gurmukhi-Gujarati Gurmukhi-Kannada Gurmukhi-Latin Gurmukhi-Malayalam Gurmukhi-Oriya Gurmukhi-Tamil Gurmukhi-Telugu Halfwidth-Fullwidth Han-Latin Han-Latin/Names Hangul-Latin Hans-Hant Hant-Hans Hebrew-Latin Hebrew-Latin/BGN Hiragana-Katakana Hiragana-Latin IPA-XSampa Jamo-Latin Kannada-Bengali Kannada-Devanagari Kannada-Gujarati Kannada-Gurmukhi Kannada-Latin Kannada-Malayalam Kannada-Oriya Kannada-Tamil Kannada-Telugu Katakana-Hiragana Katakana-Latin Katakana-Latin/BGN Kazakh-Latin/BGN Kirghiz-Latin/BGN Korean-Latin/BGN Latin-ASCII Latin-Arabic Latin-Armenian Latin-Bengali Latin-Bopomofo Latin-Cyrillic Latin-Devanagari Latin-Georgian Latin-Greek Latin-Greek/UNGEGN Latin-Gujarati Latin-Gurmukhi Latin-Hangul Latin-Hebrew Latin-Hiragana Latin-Jamo Latin-Kannada Latin-Katakana Latin-Malayalam Latin-NumericPinyin Latin-Oriya Latin-Syriac Latin-Tamil Latin-Telugu Latin-Thaana Latin-Thai Macedonian-Latin/BGN Malayalam-Bengali Malayalam-Devanagari Malayalam-Gujarati Malayalam-Gurmukhi Malayalam-Kannada Malayalam-Latin Malayalam-Oriya Malayalam-Tamil Malayalam-Telugu Maldivian-Latin/BGN Mongolian-Latin/BGN NumericPinyin-Latin NumericPinyin-Pinyin Oriya-Bengali Oriya-Devanagari Oriya-Gujarati Oriya-Gurmukhi Oriya-Kannada Oriya-Latin Oriya-Malayalam Oriya-Tamil Oriya-Telugu Pashto-Latin/BGN Persian-Latin/BGN Pinyin-NumericPinyin Publishing-Any Russian-Latin/BGN Serbian-Latin/BGN Simplified-Traditional Syriac-Latin Tamil-Bengali Tamil-Devanagari Tamil-Gujarati Tamil-Gurmukhi Tamil-Kannada Tamil-Latin Tamil-Malayalam Tamil-Oriya Tamil-Telugu Telugu-Bengali Telugu-Devanagari Telugu-Gujarati Telugu-Gurmukhi Telugu-Kannada Telugu-Latin Telugu-Malayalam Telugu-Oriya Telugu-Tamil Thaana-Latin Thai-Latin Tone-Digit Traditional-Simplified Turkmen-Latin/BGN Ukrainian-Latin/BGN Uzbek-Latin/BGN XSampa-IPA az-Lower az-Title az-Upper ch-ch_FONIPA cs-cs_FONIPA cs-ja cs-ko cs_FONIPA-ja cs_FONIPA-ko dsb-dsb_FONIPA el-Lower el-Title el-Upper es-am es-es_FONIPA es-ja es-zh es_419-ja es_419-zh es_FONIPA-am es_FONIPA-es_419_FONIPA es_FONIPA-ja es_FONIPA-zh it-am it-ja ja_Latn-ko ja_Latn-ru la-la_FONIPA lt-Lower lt-Title lt-Upper nl-Title pl-ja pl-pl_FONIPA pl_FONIPA-ja ro-ja ro-ro_FONIPA ro_FONIPA-ja ru-ja ru-zh sk-ja sk-sk_FONIPA sk_FONIPA-ja tlh-tlh_FONIPA tr-Lower tr-Title tr-Upper uz_Cyrl-uz_Latn uz_Latn-uz_Cyrl yo-yo_BJ zh_Latn_PINYIN-ru Any-Null Any-Lower Any-Upper Any-Title Any-Name Name-Any Any-Remove Any-Hex/Unicode Any-Hex/Java Any-Hex/C Any-Hex/XML Any-Hex/XML10 Any-Hex/Perl Any-Hex Hex-Any/Unicode Hex-Any/Java Hex-Any/C Hex-Any/XML Hex-Any/XML10 Hex-Any/Perl Hex-Any Any-NFC Any-NFKC Any-NFD Any-NFKD Any-FCD Any-FCC Any-ch_FONIPA Any-Latin Any-Telugu Any-Gurmukhi Any-Gujarati Any-Malayalam Any-Oriya Any-Devanagari Any-Kannada Any-Tamil Any-cs_FONIPA Any-ru Any-Bengali Any-uz_Latn Any-Katakana Any-ro_FONIPA Any-zh Any-yo_BJ Any-am Any-es_419_FONIPA Any-es_FONIPA Any-sk_FONIPA Any-Hant Any-Hans Any-Hiragana Any-la_FONIPA Any-dsb_FONIPA Any-Syriac Any-Greek Any-Greek/UNGEGN Any-Cyrillic Any-Hangul Any-Bopomofo Any-Arabic Any-Thai Any-Armenian Any-Thaana Any-Georgian Any-Hebrew Any-uz_Cyrl </syntaxhighlight> =='''文字列の検索と置換'''== 文字列の検索と置換は、メモ帳でCtrl+Fとかで検索するようなものや置換する処理と同じように目的の文字列を探す方法とファイルの検索のようにワイルドカードを使う方法があり、検索して一致した文字列を置き換えるという処理も同じみですが、もうひとつの検索と置換のやり方として、正規表現(Regular Expresion)という手法があります。これはワイルドカードによる指定にさらに文字列の先頭にある特定の文字列があって、さらに特定の文字列にはさまれた部分があって、文字列の最後尾にも特定の文字があったら、その挟まれた文字の先頭グループ1、グループ2、…グループnとして、順次、変換法則にしたがって変換といった複雑な指定が可能になる手法です。正規表現は複雑なこともできるし、単純なこともできる。できるだけ複雑なモノを単純にしてから操作をする手法など、検索と置換には多岐にわたる手法が存在します。また、検索効率をあげる手法もありかなり文字列操作の中でも奥深い技術を必要とする操作です。まずは単純な検索と置換。それと簡単な正規表現にチャレンジしてみましょう。正規表現の使い方をここでは取り上げて、正規表現による問題解決手法は、ここ以外での説明にしたいと思います。 以下、ICUのRegexを使った検索と置換の正規表現による処理のサンプルです。 <syntaxhighlight lang="cpp" line start="1"> #pragma once #include "stdafx.h" #include <stdlib.h> #include <string> //std::string型定義 #include <mbstring.h> //mbs***関数 #include <iostream> //cpp cout etc 一般入出力関数 #include <locale> //Locale関数 #include <tchar.h> //TCHAR型+_tcs***関数 #include "atlstr.h" //CString,CStringA,CStringWおよびLPTSTR,LPWSTR,LPSTR,LPCTSTR,LPCWSTR,LPCSTRの定義プリプロセッサ #include "atlbase.h" //同上 #include "cstringt.h" //CStringTの定義プリプロセッサ #include <vector> //_bstr_t型を利用するプリプロセッサ #include "comutil.h" #ifdef _DEBUG #pragma comment(lib, "comsuppwd.lib") #else #pragma comment(lib, "comsuppw.lib") #endif //_bstr_t //ICU ucnvプリプロセッサ #include <unicode/ucnv.h> #include <unicode/translit.h> #include <unicode/regex.h> #ifdef _DEBUG //#pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib")//ICU Transliterate関数を使うために必要なライブラリ 正規表現関数も #pragma comment(lib, "icuucd.lib")//ICU ucnvを使うために必要なライブラリ //#pragma comment(lib, "icuiod.lib") #else #pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib") #pragma comment(lib, "icuuc.lib") #pragma comment(lib, "icuio.lib") #endif #include "UnicodeConverter.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { _tsetlocale(LC_ALL, _T("Japanese")); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 正規表現分割 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ UParseError error; UErrorCode status = U_ZERO_ERROR; int nFindCnt = 0; printf("★正規表現検索\n"); UnicodeString regex = L"[,/とやも]";//正規表現検索文字 RegexPattern* pattern = RegexPattern::compile(regex, error, status);//パターンを登録(コンパイル) assert( U_SUCCESS(status) ); UnicodeString input = L"リンゴとミカン/ナシとモモ,ごはんやおかず/おさけもつまみ,programと技術"; assert( U_SUCCESS(status) ); RegexMatcher* matcher = pattern->matcher(input, status);//入力値での正規表現検索処理をmatcherへ格納 printf("★パターンマッチ結果出力\n"); while ( matcher->find() ) { //それぞれのマッチグループの出力。パターンに部分一致(.)が無い場合はつねにグループは1で要素0番のみ for ( int32_t i = 0; i <= matcher->groupCount(); i++ ) { std::wcout << L"[" << matcher->start(i,status) << L"," << matcher->end(i,status) << L"]" << matcher->group(i,status).getTerminatedBuffer() << std::endl; assert( U_SUCCESS(status) ); } //whileループ回数をカウントして分割数を記録 nFindCnt++; std::wcout << std::endl; } //分割した回数のUnicodeString変数の配列を確保して分割結果を配列に格納。 printf("★検索された分割文字トークンの数\n"); std::wcout << nFindCnt << std::endl; printf("\n"); UnicodeString* pfruits = new UnicodeString[nFindCnt + 1]; int32_t splits = pattern->split(input, pfruits, nFindCnt + 1, status);//登録されたパターンで分割処理 //splitの引数には入力文字列,要素が確保された出力文字列配列変数,分割数,実行結果 assert( U_SUCCESS(status) ); printf("★分割抽出した配列の出力\n"); //分割によりそれぞれに格納された文字を文字列配列の全出力で確認 for ( int32_t i = 0; i < splits; i++ ) { std::wcout << pfruits[i].getTerminatedBuffer() << std::endl; //std::wcout << (*(pfruits + i)).getTerminatedBuffer() << std::endl;こうやって表現しても同じ。 } printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 正規表現置換 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ UnicodeString replacement = L"+"; /* * 先頭置換 : replaceFirst */ printf("★先頭置換\n"); UnicodeString result = matcher->replaceFirst(replacement, status); assert( U_SUCCESS(status) ); std::wcout << result.getTerminatedBuffer() << std::endl; /* * 一括置換 : replaceAll */ printf("★一括置換\n"); result = matcher->replaceAll(replacement, status); assert( U_SUCCESS(status) ); std::wcout << result.getTerminatedBuffer() << std::endl; /* * 追記置換 : appendReplacement/appendAll 前方から逐次置換してresultに追加していく方式 */ printf("★追記置換\n"); result = L""; matcher->reset(); while ( matcher->find() ) { matcher->appendReplacement(result, replacement, status); assert( U_SUCCESS(status) ); //最後の置換完了状態で一時出力 std::wcout << result.getTerminatedBuffer() << std::endl; } //最後の置換以降の残った文字列を追加 matcher->appendTail(result); std::wcout << result.getTerminatedBuffer() << std::endl; printf("\n"); //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // 部分一致 //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ /* * 部分マッチ"(.)"の置換 */ regex = L"(.)([,/とやも]|$)";//正規表現検索文字 区切り文字or終端の一文字手前 $1を置換 区切り文字or終端は $2 replacement = L"★";//伏字に置換 result = input; pattern = RegexPattern::compile(regex, error, status); matcher = pattern->matcher(input, status); printf("★パターンマッチ結果出力\n"); while ( matcher->find() ) { //それぞれのマッチグループの出力。パターンに部分一致(.)が無い場合はつねにグループは1で要素0番のみ for ( int32_t i = 0; i <= matcher->groupCount(); i++ ) { std::wcout << L"[" << matcher->start(i,status) << L"," << matcher->end(i,status) << L"]" << matcher->group(i,status).getTerminatedBuffer() << std::endl; assert( U_SUCCESS(status) ); } //whileループ回数をカウントして分割数を記録 nFindCnt++; std::wcout << std::endl; } typedef std::pair<int32_t,int32_t> range_type; std::vector<range_type> matches; matcher->reset(); while ( matcher->find() ) { // 第一グループを保存する 条件:$1 が存在して、検索の開始文字位置と終了文字位置が0以上なら保存 if(matcher->groupCount() >= 1 && matcher->start(1,status) > 0 && matcher->end(1,status) > 0 ){ matches.push_back(range_type(matcher->start(1,status), matcher->end(1,status))); assert( U_SUCCESS(status) ); } } // 末尾から置換 while ( !matches.empty() ) { range_type range = matches.back(); matches.pop_back(); result.replace(range.first, range.second - range.first, replacement); } printf("★部分一致パターンの置換結果出力\n"); std::wcout << result.getTerminatedBuffer() << std::endl; delete[] pfruits; delete matcher; delete pattern; return 0; } </syntaxhighlight> 出力結果 <syntaxhighlight lang="text"> ★正規表現検索 ★パターンマッチ結果出力 [3,4]と [7,8]/ [10,11]と [13,14], [17,18]や [21,22]/ [25,26]も [29,30], [37,38]と ★検索された分割文字トークンの数 9 ★分割抽出した配列の出力 リンゴ ミカン ナシ モモ ごはん おかず おさけ つまみ program 技術 ★先頭置換 リンゴ+ミカン/ナシとモモ,ごはんやおかず/おさけもつまみ,programと技術 ★一括置換 リンゴ+ミカン+ナシ+モモ+ごはん+おかず+おさけ+つまみ+program+技術 ★追記置換 リンゴ+ リンゴ+ミカン+ リンゴ+ミカン+ナシ+ リンゴ+ミカン+ナシ+モモ+ リンゴ+ミカン+ナシ+モモ+ごはん+ リンゴ+ミカン+ナシ+モモ+ごはん+おかず+ リンゴ+ミカン+ナシ+モモ+ごはん+おかず+おさけ+ リンゴ+ミカン+ナシ+モモ+ごはん+おかず+おさけ+つまみ+ リンゴ+ミカン+ナシ+モモ+ごはん+おかず+おさけ+つまみ+program+ リンゴ+ミカン+ナシ+モモ+ごはん+おかず+おさけ+つまみ+program+技術 ★パターンマッチ結果出力 [2,4]ゴと [2,3]ゴ [3,4]と [6,8]ン/ [6,7]ン [7,8]/ [9,11]シと [9,10]シ [10,11]と [12,14]モ, [12,13]モ [13,14], [16,18]んや [16,17]ん [17,18]や [20,22]ず/ [20,21]ず [21,22]/ [24,26]けも [24,25]け [25,26]も [28,30]み, [28,29]み [29,30], [36,38]mと [36,37]m [37,38]と [39,40]術 [39,40]術 [40,40] ★部分一致パターンの置換結果出力 リン★とミカ★/ナ★とモ★,ごは★やおか★/おさ★もつま★,progra★と技★ </syntaxhighlight> 149行目以降に記述した部分一致からのプログラムはやや複雑な表記になっていますが、これはICUに準備された関数だけでは部分一致の処理ができないために自分で工夫をしなければならないことに起因しています。 169行目のtypedef関数は宣言を置き換えるための命令文になります。std::pair<int32_t,int32_t>という構造体定義をrange_typeに置き換えるということを意味しています。 またpairの後ろにある<int32_t,int32_t>というのはpairという構造体がテンプレート構造体として準備されていて、二つの型名を引数にとる必要がありここではint32_tという型を2つ指定して、pairというテンプレート構造体で使う2つの型はどちらもint型で使いますというテンプレート構造体の利用方法を記述している部分になります。pair構造体は2つの変数を対にして記憶するための構造体になっています。 170行目のvectorという関数もテンプレートクラスになっていて、要するにstd::vector< std::pair<int32_t,int32_t> >という宣言をしたのと同じことで、vectorクラスはstd::pair<int32_t,int32_t>という型で使いますという準備をした上でその変数として、matchesというものを使うという定義になります。vecotrは動的にメモリを確保するのを支援してくれるクラスで、push_backという関数の引数にstd::pair<int32_t,int32_t>(int型の数値,int型の数値)という構造体が持つコンストラクタによって返されるpair構造体型のポインタを記録しています。引数には検索した文字の開始位置と終了位置を入れています。vectorのbackという関数で最後に格納したポインタを返してくれるので、range_typeつまりstd::pair<int32_t,int32_t>型のrangeというポインタ変数にコピーしています。std::pairのメンバ変数firstにコンストラクタで使用した一つ目引数の数値が取得でき、メンバ変数secondで二つ目の引数の数値が取得できます。vecotorクラスのpop_back()という関数の呼び出しによって最後に格納したポインタを消すという処理をしてくれます。こうやってfind()で検索するすべての検索位置をvectorクラスの中にpair構造体でセットした2つのint型整数で検索された文字の開始位置と終了位置を記憶する仕組みです。テンプレートクラスやテンプレート構造体やクラスについて理解する必要があります。vectorのempty()関数は格納されたものが無くなったらtrueを返す関数で、while文のループ条件として!matches.empty()のようにして、空っぽではないあいだ繰り返すという処理になっています。 部分一致の処理は難しいので、typedef関数とクラスと構造体のコンストラクタとテンプレートクラスとクラスのメンバ関数およびクラスのメンバ変数、更には標準クラスであるvectorクラスとpair構造体について理解してから戻ってくるとよいかもしれません。 ICUを使わない文字列検索としてはstrchのような***ch系の検索関数があります。見つかった位置のByte数を返してくれます。ICUの正規表現に比べると機能性は低いです。一文字を引数にするとき符号なし整数型にしなければいけないあたりは、初期値を与えての検索は楽ですが、実際に一文字の文字列から検索しようとすると大変なのかもしれません。実際に数えてみないと、一文字あたりが、1バイトなのか2バイトなのかわからないし…。総合的に検索を支援してくれるICUの正規表現がいかに楽なのかがわかります。 <syntaxhighlight lang="cpp" line start="1"> #pragma once #include "stdafx.h" #include <stdlib.h> #include <string> //std::string型定義 #include <mbstring.h> //mbs***関数 #include <iostream> //cpp cout etc 一般入出力関数 #include <locale> //Locale関数 #include <tchar.h> //TCHAR型+_tcs***関数 #include "atlstr.h" //CString,CStringA,CStringWおよびLPTSTR,LPWSTR,LPSTR,LPCTSTR,LPCWSTR,LPCSTRの定義プリプロセッサ #include "atlbase.h" //同上 #include "cstringt.h" //CStringTの定義プリプロセッサ #include <vector> //_bstr_t型を利用するプリプロセッサ #include "comutil.h" #ifdef _DEBUG #pragma comment(lib, "comsuppwd.lib") #else #pragma comment(lib, "comsuppw.lib") #endif //_bstr_t //ICU ucnvプリプロセッサ #include <unicode/ucnv.h> #include <unicode/translit.h> #include <unicode/regex.h> #ifdef _DEBUG //#pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib")//ICU Transliterate関数を使うために必要なライブラリ 正規表現関数も #pragma comment(lib, "icuucd.lib")//ICU ucnvを使うために必要なライブラリ //#pragma comment(lib, "icuiod.lib") #else #pragma comment(lib, "icudt.lib") #pragma comment(lib, "icuind.lib") #pragma comment(lib, "icuuc.lib") #pragma comment(lib, "icuio.lib") #endif #include "UnicodeConverter.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { int SingleChr = 'r'; unsigned int mbSingleString; unsigned int nKeta; char pcSingleStr[] = "列"; unsigned char mbstring[] = "日本語の検索用文字列です。"; char pcString[] = "日本語の検索用文字列です。The quick brown dog jumps over the lazy fox"; char fmt1[] = " 1 2 3 4 5 6"; char fmt2[] = "123456789012345678901234567890123456789012345678901234567890123456789"; char *pcPos; unsigned char *pucPos; unsigned char *pucRusultPos; int result; int result2; printf_s( "文字列検索:\n\n %s\n", pcString ); printf_s( " %s\n %s\n\n", fmt1, fmt2 ); //★マルチバイト対応1文字の文字列で検索。 printf_s( "★マルチバイト対応検索\n"); pucPos = (unsigned char*)pcSingleStr; pucPos = _mbsinc(pucPos);//一文字分ポインタを進める関数 result = (int)(pucPos - (unsigned char*)pcSingleStr); mbSingleString = 0; nKeta = 1; for(int n = 0; n < result; n++){ mbSingleString = mbSingleString + (*(pucPos - (n + 1))) * (nKeta); printf_s( "%02x \n", (*(pucPos - (n + 1)))); nKeta = nKeta * 0x100; } //printf_s( "%02x%02x\n", *(pucPos - 2), *(pucPos - 1));このカタチをunsigned int の変数に変形したのが mbSingleString //unsigned int mbstringString = 'の';とかでも検索できますが、strcpy関数とかでコピーしてきた一文字の文字列でサンプル printf_s( "MultiByteString検索文字 SigngleWord:%04x(%s)\n", mbSingleString, pcSingleStr); printf_s( "incriment:%d[Byte]\n\n",result); pucRusultPos = _mbschr((unsigned char*)pcString, mbSingleString); result2 = (int)(pucRusultPos - (unsigned char*)pcString + 1); if ( pucRusultPos != NULL ) printf_s( "検索結果: 最初の %04x(%s) が見つかった位置は %d[Byte]目\n", mbSingleString, pcSingleStr, result2 ); else printf_s( "検索結果: %s not found\n\n", pcSingleStr ); //★シングルバイト文字検索。 printf_s( "\n\n"); printf_s( "★シングルバイト文字の初期値による検索\n"); printf_s( "検索文字: %c\n", SingleChr ); //前方検索 pcPos = strchr( pcString, SingleChr ); result = (int)(pcPos - pcString + 1); if ( pcPos != NULL ) printf_s( "検索結果: 最初の %c が見つかった位置は %d[Byte]目\n", SingleChr, result ); else printf_s( "検索結果: %c not found\n", SingleChr ); //後方検索 pcPos = strrchr( pcString, SingleChr ); result = (int)(pcPos - pcString + 1); if ( pcPos != NULL ) printf_s( "検索結果: 最後に %c が見つかった位置は %d[Byte]目\n", SingleChr, result ); else printf_s( "検索結果:\t%c not found\n", SingleChr ); return 0; } </syntaxhighlight> =='''文字列ファイルパス操作'''== ファイルパスにも日本語文字列が使われますし、検索やフォルダ作成、フォルダのコピーといった作業をしたあと、フルパスを保持する必要があったりもします。ファイルの全検索こそが文字列の検索でもあるわけで、パス名操作には文字列連結や拡張子の抽出。Tokenによる階層深さの探索。使用禁止文字チェックと文字列操作の応用が必要になります。 =='''文字列ファイル名操作'''== 文字列の操作でありながら、ファイルの名前を変更するという処理も少し特別な作業になります。拡張子の抽出も実施する必要があります。 =='''文字列ファイルへの入出力'''== ここまで、やってきた手法で文字列をファイルに保存することをやってみます。文字列はかならずしもテキストファイルとして保管されるものではありません。DBに格納されるもの、バイナリファイルに格納されるもの、圧縮されるもの、様々です。ここでは一般的なテキストファイルとして保管し、簡単なテキストDBとしての操作について作業します。 =='''文字列と数値の変換'''== 実際のアプリケーションでは、数値の入力を行う部分でも、文字コードとして入力がなされ、各種のエディタや、エディットコントロール、入力画面からは文字としてテキストから渡されます。このように取り扱われる文字列としての数値を、プログラミング言語の数を扱う型に格納する技術が必要になります。 =='''文字列と日付・日時・時間の変換'''== 先述の数値の問題と同様、日付・日時・時間も文字列として与えられる場合があり、時制を扱う型との相互変換を行う技術も必要になります。 <!-- {|class="wikitable" !上位ビッツ\下位ビッツ!!0!!1!!2!!3!!4!!5!!6!!7!!8!!9!!A!!B!!C!!D!!E!!F |- |0||NUL||SOH||STX||ETX||EOT||ENQ||ACK||BEL|||BS||HT||LF||VT||FF||CR||SO||SI |- |1||DLE||DC1||DC2||DC3||DC4||NAK||SYN||ETB||CAN||EM||SUB||ESC||IS4||IS3||IS2||IS1 |- |2||SP||!||"||#||$||%||&||'||(||)||*||+||,||-||.||/ |- |3||0||1||2||3||4||5||6||7||8||9||:||;||<||=||>||? |- |4||@||A||B||C||D||E||F||G||H||I||J||K||L||M||N||O |- |5||P||Q||R||S||T||U||V||W||X||Y||Z||[||\||]||^||_ |- |6||`||a||b||c||d||e||f||g||h||i||j||k||l||m||n||o |- |7||p||q||r||s||t||u||v||w||x||y||z||{|| | ||} ||~||DEL |- |} {|class="wikitable" !上位ビッツ\下位ビッツ!!0!!1!!2!!3!!4!!5!!6!!7!!8!!9!!A!!B!!C!!D!!E!!F |- |8||||||BPH||NBH||||NEL||SSA||ESA||HTS||HTJ||VTS||PLD||PLU||RI||SS2||SS3 |- |9||DCS||PU1||PU2||STS||CCH||MW||SPA||EPA||SOS||||SCI||CSI||ST||OSC||PM||APC |- |A||||。||「||」||、||・||ヲ||ァ||ィ||ゥ||ェ||ォ||ャ||ュ||ョ||ッ |- |B||ー||ア||イ||ウ||エ||オ||カ||キ||ク||ケ||コ||サ||シ||ス||セ||ソ |- |C||タ||チ||ツ||テ||ト||ナ||ニ||ヌ||ネ||ノ||ハ||ヒ||フ||ヘ||ホ||マ |- |D||ミ||ム||メ||モ||ヤ||ユ||ヨ||ラ||リ||ル||レ||ロ||ワ||ン||゙||゚ |- |E|||||||||||||||||||||||||||||||| |- |F|||||||||||||||||||||||||||||||| |- -->
C 文字列操作
に戻る。
個人用ツール
ログイン
名前空間
ページ
議論
変種
表示
閲覧
ソースを表示
履歴表示
操作
検索
案内
メインページ
コミュニティ・ポータル
最近の出来事
最近の更新
おまかせ表示
ヘルプ
ツールボックス
リンク元
関連ページの更新状況
特別ページ