C 文字列操作 新しいページはコチラ
提供: yonewiki
(→文字列ファイルへの入出力) |
(→文字列ファイルへの入出力) |
||
4,820行: | 4,820行: | ||
次はファイル出力にあたる書き込みですね。 | 次はファイル出力にあたる書き込みですね。 | ||
+ | <syntaxhighlight lang="cpp" line start="1"> | ||
+ | //JISからUTF-16LEへの変換処理 | ||
+ | |||
+ | UConverter* ucnvTest; | ||
+ | UErrorCode uerrorNum; | ||
+ | int nStrSize; | ||
+ | int nStrResultSize; | ||
+ | char pcStrUTF16LEBOM[] = "\xFF\xFE"; | ||
+ | char pcStrUTF8BOM[] = "\xEF\xBB\xBF"; | ||
+ | nStrSize = nSize; | ||
+ | |||
+ | std::wstring stringCnvResult(nStrSize, L'\0'); | ||
+ | |||
+ | ucnvTest = ucnv_open("iso-2022-jp", &uerrorNum); | ||
+ | nStrResultSize = ucnv_toUChars( | ||
+ | ucnvTest, | ||
+ | &stringCnvResult[0], stringCnvResult.size(), // 変換先のポインタとサイズ | ||
+ | &pcStrFile[0], nStrSize, // 変換元のポインタとサイズ | ||
+ | &uerrorNum | ||
+ | ); | ||
+ | stringCnvResult.resize(nStrResultSize); | ||
+ | ucnv_close(ucnvTest); | ||
+ | _tprintf(_T("%s\n"), stringCnvResult.c_str()); | ||
+ | printf("\n"); | ||
+ | |||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | //★UTF16LEのTextモードでの書き込み | ||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | |||
+ | //\n 0x0Aが \r\nに変換されるため、Binaryモードで読み込んだ\r\nを保持した文字列から | ||
+ | //変換した文字列をテキストモードで書き込むと\r\r\nのように2重復帰が書き込まれる。 | ||
+ | //テキストエディタでは\rひとつでも、改行されるため \r と \r\nで2つ改行になる。 | ||
+ | |||
+ | errNo = _wfopen_s( &pfileText, pwcStrFilePathNewTexttoBinary, L"w,ccs=UTF-16LE"); | ||
+ | fputws(stringCnvResult.c_str(), pfileText); | ||
+ | fclose(pfileText); | ||
+ | |||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | //★UTF16LEのBinaryモードテキストの書き込み | ||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | |||
+ | errNo = _wfopen_s( &pfileText, pwcStrFilePathNewUTF16LE, L"wb"); | ||
+ | fputs(pcStrUTF16LEBOM,pfileText); | ||
+ | fputws(stringCnvResult.c_str(), pfileText); | ||
+ | fclose(pfileText); | ||
+ | |||
+ | //UnicodeUTF-16LEのutf-8への変換処理 | ||
+ | ucnvTest = ucnv_open("UTF-8", &uerrorNum); | ||
+ | |||
+ | nStrSize = stringCnvResult.size(); | ||
+ | std::string stringCnvResult3(ucnv_getMaxCharSize(ucnvTest) * nStrSize , L'\0'); | ||
+ | |||
+ | |||
+ | nStrResultSize = ucnv_fromUChars( | ||
+ | ucnvTest, | ||
+ | &stringCnvResult3[0], stringCnvResult3.size(), // 変換先のポインタとサイズ | ||
+ | &stringCnvResult[0], nStrSize, // 変換元のポインタとサイズ | ||
+ | &uerrorNum | ||
+ | ); | ||
+ | stringCnvResult3.resize(nStrResultSize); | ||
+ | ucnv_close(ucnvTest); | ||
+ | printf("%s\n", stringCnvResult3.c_str()); | ||
+ | |||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | //★UTF8のBOM無しテキストの書き込み | ||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | |||
+ | errNo = _wfopen_s( &pfileText, pwcStrFilePathNewUTF8, L"wb"); | ||
+ | //fputs(pcStrUTF8BOM,pfileText); | ||
+ | fputs(stringCnvResult3.c_str(), pfileText); | ||
+ | fclose(pfileText); | ||
+ | |||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | //★UTF8のBOM有りテキストの書き込み | ||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | |||
+ | errNo = _wfopen_s( &pfileText, pwcStrFilePathNewUTF8BOM, L"wb"); | ||
+ | fputs(pcStrUTF8BOM,pfileText); | ||
+ | fputs(stringCnvResult3.c_str(), pfileText); | ||
+ | fclose(pfileText); | ||
+ | </syntaxhighlight> | ||
+ | 先述の読み込み処理に続けてのプログラムになります。ファイルオープンモードでwを指定して、fputs関数でchar型の書き込み、fputwsでwchar_t型の書き込みをするような形式です。モードaで追記なので先頭の行に追記されます。ファイルの最後尾に追加するときはファイルポジションをfsetpos関数で移動してからfputws/fputsで書き込むと良いでしょう。新規のファイル作成となるモードwのバイナリモードwbでは、BOMコードを付与しなければならないケースも出てきます。fputsでBOMコードを保持した文字列を引数にすると良いです。bを付けないテキストモードでの書き込みでは、ccs=UTF-8やccs=UTF-16LEを指定すると自動でBOMコードを追記してくれますので、そのままUTF-16ならwchar_t型の文字列を書き出せばよいです。但し、バイナリモードで読み込んだ文字列は\r\nがそのまま文字列になっているので、書き出し時に後ろの\nが\r\nに変換され、\r\r\nになってしまうので、バイナリモードで読み込んだ文字をテキストモードで書き出すのはやめた方がいいです。どうしても相互乗り換えするのであれば、改行コードの置換処理が必要です。UTF-8のテキストモード書き込みでもユニコードのUTF-16LE形式で書き込むことでUTF-8に変換されますので、プログラム内部ではUnicodeで文字列を扱った方が効率が良いと思います。テキストモードでサポートしない文字コードのような特殊な形式に変換する場合はバイナリモードで文字列を読み込んで、変換処理を実施し、char型に格納した文字コードをバイナリモードで書き出すと良いでしょう。サンプルプログラムではテキストモードで読み込んだJIS文字をUnicodeに変換しUTF-16テキストモードで書き込んだ失敗例をプログラムにしてあります。ファイルオープンモードをうまく使いこなすことと、Unicode以外の文字列はchar型でバイナリとして扱うところがポイントです。変換処理はICUに任せればかなり柔軟な入出力処理が作れると思います。 | ||
+ | |||
+ | |||
+ | ここの長ったらしい文字列処理の説明の総括的なプログラミングになっているかと思います。全部理解してこそ、やりきれる処理です。文字列処理のプログラムを普段作らない自分でもこの程度なら理解しておきたいものです。ここのサンプルは直線的なプログラムで無駄の多いサンプルです。みなさんはもっともっと効率のいい文字列処理をやって下さい。ここでは関数の引数や、クラスの考え方をあまり知らなくても、文字列処理ができるように、あまり多くの技術を使わないそういう無駄なサンプルになっていますが、上から順番に処理していくだけなので、処理の順番は理解しやすいようになっているのではないかと自負するところです。あとは文字コードの自動判定くらいを触れて、文字列処理に関するこの記事は終了にしたいなぁと思います。誰も読まないかもしれないのに、よくこんなにウダウダと長ったらしい文章を書いたなぁ。恐るべしだ。でも、こういううだうだした説明ともっと若いときに出会っていたら、もっと手早く理解できたのになぁと自分は思います。この長い文書が誰かの役に立っていたなら幸せなことです。 | ||
=='''文字列と数値の変換'''== | =='''文字列と数値の変換'''== |