C 文字列操作 新しいページはコチラ
提供: yonewiki
(→文字列ファイルへの入出力) |
(→文字列ファイルへの入出力) |
||
4,495行: | 4,495行: | ||
FILE* pfileText; | FILE* pfileText; | ||
errno_t errNo; | errno_t errNo; | ||
+ | size_t* psizeRuturnValue = new size_t; | ||
int nCloseCnt; | int nCloseCnt; | ||
wchar_t pwcStrFilePathShiftJIS[] = L"C:\\...\\...\\...\\test.txt";//...\\...\\...には正確なパスを指定。 | wchar_t pwcStrFilePathShiftJIS[] = L"C:\\...\\...\\...\\test.txt";//...\\...\\...には正確なパスを指定。 | ||
+ | wchar_t pwcStrFilePathJIS[] = L"C:\\...\\...\\...\\test_jis.txt"; | ||
+ | wchar_t pwcStrFilePathEUC[] = L"C:\\...\\...\\...\\test_euc.txt"; | ||
wchar_t pwcStrFilePathUtf8Bom[] = L"C:\\...\\...\\...\\test_utf8.txt"; | wchar_t pwcStrFilePathUtf8Bom[] = L"C:\\...\\...\\...\\test_utf8.txt"; | ||
wchar_t pwcStrFilePathUtf8[] = L"C:\\...\\...\\...\\test_utf8N.txt"; | wchar_t pwcStrFilePathUtf8[] = L"C:\\...\\...\\...\\test_utf8N.txt"; | ||
4,530行: | 4,533行: | ||
//Unicodeサンプル文字 1行目 | //Unicodeサンプル文字 1行目 | ||
− | printf("文字コードUTF- | + | printf("文字コードUTF-16->"); |
for(int i=0; i < (int)wcslen(pwcStrGohan) + 1; i++){ | for(int i=0; i < (int)wcslen(pwcStrGohan) + 1; i++){ | ||
printf("%04x:",*(pwcStrGohan + i)); | printf("%04x:",*(pwcStrGohan + i)); | ||
4,539行: | 4,542行: | ||
while(!feof(pfileText)){ | while(!feof(pfileText)){ | ||
− | pwcStrErr = fgetws(pwcStrStream,1024,pfileText);// | + | pwcStrErr = fgetws(pwcStrStream,1024,pfileText);//最終行がEOFのみの場合に失敗して1行前の値が残ることに注意。 |
− | //先頭からUTF- | + | //先頭からUTF-8→UTF16形式で文字列を取得する。 |
− | wprintf(L"%s(%s)\n", pwcStrStream, pwcStrErr);//UTF- | + | wprintf(L"%s(%s)\n", pwcStrStream, pwcStrErr);//UTF-16のpwcStrStreamをSJIS(Locale設定)で書き出し。UTF-16のままだと文字化けする。 |
− | printf("文字コードUTF- | + | printf("文字コードUTF-16->"); |
for(int i=0 ;i < 20 ;i++){ //Unicodeに変換された文字コードを先頭20文字だけ出力。 | for(int i=0 ;i < 20 ;i++){ //Unicodeに変換された文字コードを先頭20文字だけ出力。 | ||
printf("%04x:",*(pwcStrStream + i)); | printf("%04x:",*(pwcStrStream + i)); | ||
4,562行: | 4,565行: | ||
//★★★★★★★★★★★★★★★★★★★★★★★★ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
− | // | + | //★UTF8のBOM有りテキストの読み込み |
//★★★★★★★★★★★★★★★★★★★★★★★★ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
− | printf(" | + | printf("★UTF8のBOM有りテキストの読み込み\n"); |
errNo = _wfopen_s( &pfileText, pwcStrFilePathUtf8Bom, L"r,ccs=UTF-8"); | errNo = _wfopen_s( &pfileText, pwcStrFilePathUtf8Bom, L"r,ccs=UTF-8"); | ||
printf("Error?->%d\n", errNo); | printf("Error?->%d\n", errNo); | ||
4,575行: | 4,578行: | ||
while(!feof(pfileText)){ | while(!feof(pfileText)){ | ||
− | pwcStrErr = fgetws(pwcStrStream,1024,pfileText);// | + | pwcStrErr = fgetws(pwcStrStream,1024,pfileText);//最終行がEOFのみの場合に失敗して1行前の値が残ることに注意。 |
− | //UTF-8(BOMはEF BB BFなので4バイト目) | + | //UTF-8(BOMはEF BB BFなので4バイト目)からUTF16形式で文字列を取得する。 |
//※FE FFをUTF-8でエンコードするとEF BB BF | //※FE FFをUTF-8でエンコードするとEF BB BF | ||
//※FE FF = 1111 1110 1111 1111 を | //※FE FF = 1111 1110 1111 1111 を | ||
4,608行: | 4,611行: | ||
while(!feof(pfileText)){ | while(!feof(pfileText)){ | ||
− | pwcStrErr = fgetws(pwcStrStream,1024,pfileText);// | + | pwcStrErr = fgetws(pwcStrStream,1024,pfileText);//最終行がEOFのみの場合に失敗して1行前の値が残ることに注意。 |
− | if(pwcStrErr != NULL ){ //UTF-16(BOMはFE FFなので3バイト目) | + | if(pwcStrErr != NULL ){ //UTF-16(BOMはFE FFなので3バイト目)からUTF16形式で文字列を取得する。 |
− | wprintf(L"%s", pwcStrStream);//UTF- | + | wprintf(L"%s", pwcStrStream);//UTF-16のpwcStrStreamをSJIS(Locale設定)で書き出し。UTF-16のままだと文字化けする。 |
} | } | ||
} | } | ||
4,633行: | 4,636行: | ||
printf("test.txtテキストファイルの中身\n"); | printf("test.txtテキストファイルの中身\n"); | ||
while(!feof(pfileText)){ | while(!feof(pfileText)){ | ||
− | + | ||
− | pcStrErr = fgets(pcStrStream, 1024, pfileText);// | + | pcStrErr = fgets(pcStrStream, 1024, pfileText);//最終行がEOFのみの場合に失敗して1行前の値が残ることに注意。 |
if(pcStrErr != NULL ){ | if(pcStrErr != NULL ){ | ||
printf("%s", pcStrStream); | printf("%s", pcStrStream); | ||
4,644行: | 4,647行: | ||
nCloseCnt = fclose(pfileText); | nCloseCnt = fclose(pfileText); | ||
printf("nCloseErr->%d\n", nCloseCnt); | printf("nCloseErr->%d\n", nCloseCnt); | ||
+ | printf("\n"); | ||
+ | |||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | //★JISテキストの読み込み | ||
+ | //★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | |||
+ | //int型でchar配列のサイズを動的に確保ができるので、int型の範囲のファイルなら | ||
+ | //一度に格納できるプログラムになっています。intの範囲を超えると動的メモリ確保で | ||
+ | //失敗します。その先の工夫はまた別途考える必要があります。少し筒変換したり…。 | ||
+ | |||
+ | int nSize = 0; | ||
+ | int nFeedCnt = 0; | ||
+ | |||
+ | char* pcStrFile; | ||
+ | fpos_t* pfposStartPos = new fpos_t; | ||
+ | printf("★JISテキストの読み込み\n"); | ||
+ | errNo = _wfopen_s( &pfileText, pwcStrFilePathJIS, L"rb"); | ||
+ | printf("Error?->%d\n", errNo); | ||
+ | |||
+ | fgetpos(pfileText, fposPos); | ||
+ | printf("fpos-> %04d\n", *fposPos); //ファイルを開いた時点でのポジションの確認。 | ||
+ | |||
+ | printf("test_jis.txtテキストファイルの中身\n"); | ||
+ | fgetpos(pfileText, pfposStartPos); | ||
+ | while(!feof(pfileText)){ | ||
+ | nSize = nSize + nFeedCnt * 1024; | ||
+ | nFeedCnt++; | ||
+ | *psizeRuturnValue = fread(pcStrStream, sizeof(char), 1024, pfileText);//最終行がEOFのみの場合に失敗して1行前の値が残ることに注意。 | ||
+ | fgetpos(pfileText, fposPos); | ||
+ | for(int i = 0; i < *fposPos; i++){ | ||
+ | printf("%02x:",0x000000FF & *(pcStrStream + i)); | ||
+ | } | ||
+ | } | ||
+ | printf("[EOF]"); | ||
+ | printf("\n"); | ||
+ | |||
+ | nSize = nSize + (int)*fposPos - ((nFeedCnt - 1) * 1024); | ||
+ | fsetpos(pfileText, pfposStartPos); | ||
+ | pcStrFile = new char[nSize + 1]; | ||
+ | while(!feof(pfileText)){ | ||
+ | *psizeRuturnValue = fread(pcStrFile, sizeof(char), nSize + 1, pfileText);//最終行がEOFのみの場合に失敗して1行前の値が残ることに注意。 | ||
+ | for(int i = 0; i < nSize; i++){ | ||
+ | printf("%02x:",0x000000FF & *(pcStrFile + i)); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | printf("[EOF]"); | ||
+ | printf("\n"); | ||
+ | fgetpos(pfileText, fposPos); | ||
+ | printf("fpos-> %04d\npReturnValue-> %04d\n", *fposPos, *psizeRuturnValue); //ファイルを開いた時点でのポジションの確認。 | ||
+ | |||
+ | |||
+ | nCloseCnt = fclose(pfileText); | ||
+ | printf("nCloseErr->%d\n", nCloseCnt); | ||
+ | printf("\n"); | ||
+ | |||
+ | UConverter* ucnvTest; | ||
+ | UErrorCode uerrorNum; | ||
+ | int nStrSize; | ||
+ | int nStrResultSize; | ||
+ | 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"); | printf("\n"); | ||
return 0; | return 0; | ||
4,710行: | 4,787行: | ||
[EOF] | [EOF] | ||
nCloseErr->0 | nCloseErr->0 | ||
+ | |||
+ | ★JISテキストの読み込み | ||
+ | Error?->0 | ||
+ | fpos-> 0000 | ||
+ | test_jis.txtテキストファイルの中身 | ||
+ | 1b:24:42:24:34:24:4f:24:73:24:72:3f:29:24:59:24:3f:24:68:21:23:1b:28:4a:0d:0a:0d:0a:0d:0a:1b:24:42:24:3d:24:6c:24:40:24:31:24:40:24:68:21:23 | ||
+ | :1b:28:4a:0d:0a:[EOF] | ||
+ | 1b:24:42:24:34:24:4f:24:73:24:72:3f:29:24:59:24:3f:24:68:21:23:1b:28:4a:0d:0a:0d:0a:0d:0a:1b:24:42:24:3d:24:6c:24:40:24:31:24:40:24:68:21:23 | ||
+ | :1b:28:4a:0d:0a:[EOF] | ||
+ | fpos-> 0052 | ||
+ | pReturnValue-> 0000 | ||
+ | nCloseErr->0 | ||
+ | |||
+ | ごはんを食べたよ。 | ||
+ | |||
+ | |||
+ | それだけだよ。 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | という感じです。ごはんを食べたよ それだけだよ。というサンプルの文字列に特に深い意味はありませんが、Windowsは改行コードにCR LFを使うのが一般的です。しかしながら、ファイルから取り込んできた文字列にでは\r 0x0dは無くなって\ | + | という感じです。ごはんを食べたよ それだけだよ。というサンプルの文字列に特に深い意味はありませんが、Windowsは改行コードにCR LFを使うのが一般的です。しかしながら、ファイルから取り込んできた文字列にでは\r 0x0dは無くなって\nにあたる0x0aだけが残る仕様になっています。これらの改行復帰コードを厳密に扱う場合には書き込みするときや、文字列操作時に工夫が必要になります。文字コードがどんなふうに扱われているのか、厳密にどうなっているのか調べるためにも、時々は文字コードそのものを出力して確かめるのも大事なのではないかと思います。人間様にわかる文字だけを出力していたのでは、コンピュータを正確にあやつることは難しいです。JISの変換ではファイルオープン時にバイナリで開いています。これをchar型の変数に格納して、ICUのJIS→UNICODE変換を実施しています。 |
+ | |||
+ | テキストファイルをバイナリで読み込む場合には区切りが大事です。動的に生成できる文字列配列の大きさはint型の範囲が限界ですので、ひとつだけで扱おうとするのは無理がありますし、int型くらい大きいサイズのメモリ確保は無理があります。もう少し小さい単位で文字列を扱える工夫が必要になります。JISテキストファイルなら改行コードまでの大きさくらいが良いと思います。文字列の中に改行コードが見つかるまで文字数を計算して、それでメモリ確保をし、JIS文字列を変換して、作業用の文字列配列に格納するといった、そういう仕組みにするだけのことです。このプログラムはテキストエディタやファイルローダとしての役割を担うものではないので、そこまでの具体的な拡張には挑戦しませんでした。実際の組み込みでは、プログラムが扱うデータの大きさにちょうどよい区切りを準備することになると思います。 | ||
+ | まぁこのままでもかなり大きさまで扱えるので、コンソールで遊ぶ程度ならこれでもいいんではないでしょうか?それよか、メモリ確保がうまくいかない場合の例外処理とか追加しますかね。そのあたりの説明はまた別の項目になるかと思います。 | ||
=='''文字列と数値の変換'''== | =='''文字列と数値の変換'''== |