日本語とラテン文字が混在するマルチバイト文字列があります。この文字列の一部を別のメモリ位置にコピーしようとしています。マルチバイト文字列であるため、一部の文字は1バイトを使用し、他の文字は2バイトを使用します。文字列の一部をコピーするときは、「半分」の日本語の文字をコピーしてはいけません。これを適切に実行できるようにするには、マルチバイト文字列の文字の開始位置と終了位置を判別できる必要があります。
たとえば、文字列に[2バイト][2バイト][1バイト]を必要とする3文字が含まれている場合、3ではなく2、4、または5バイトを他の場所にコピーする必要があります。 2番目の文字の半分だけをコピーします。
マルチバイト文字列の文字の開始位置と終了位置を把握するために、Windows API関数のCharNextとCharNextExAを使用しようとしていますが、運がありません。これらの関数を使用すると、一度に1文字ではなく、一度に1バイトずつ文字列をナビゲートします。MSDNによると、CharNextは文字列内の次の文字へのポインタを取得することになっています。。
この問題を説明するためのコードを次に示します。
#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
/* string consisting of six "asian" characters */
wchar_t wcsString[] = L"\u9580\u961c\u9640\u963f\u963b\u9644";
int main()
{
// Convert the asian string from wide char to multi-byte.
LPSTR mbString = new char[1000];
WideCharToMultiByte( CP_UTF8, 0, wcsString, -1, mbString, 100, NULL, NULL);
// Count the number of characters in the string.
int characterCount = 0;
LPSTR currentCharacter = mbString;
while (*currentCharacter)
{
characterCount++;
currentCharacter = CharNextExA(CP_UTF8, currentCharacter, 0);
}
}
(メモリリークとエラーチェックの失敗は無視してください。)
さて、上記の例では、characterCountが6になると予想します。これは、アジアの文字列の文字数だからです。ただし、mbStringには18文字が含まれているため、代わりにcharacterCountは18になります。
門阜陀阿阻附
それがどのように機能するのかわかりません。CharNextは、文字列内の「é–€é」が日本語文字のエンコードされたバージョンであるか、実際には文字é–€およびéであるかをどのように認識しますか?
いくつかのメモ:
- すべての開発者がUnicodeについて知っておくべきことについてのJoelsブログ投稿を読みました。私はその中に何かを誤解したかもしれません。
- 文字数を数えるだけなら、アジアの文字列の文字数を直接数えることができます。私の本当の目標は、マルチバイト文字列の一部を別の場所にコピーすることであることに注意してください。別の場所はマルチバイトのみをサポートし、ワイド文字はサポートしません。
- MultiByteToWideCharを使用してmbStringの内容をワイド文字に戻すと、正しい文字列(門襲陀阿訓附)が得られます。これは、mbStringに問題がないことを示しています。
編集:明らかに、CharNext関数はUTF-8をサポートしていませんが、Microsoftはそれを文書化するのを忘れていました。私は自分のルーチンを一緒に投げたりコピーしたりしましたが、それは使用せず、改善する必要があります。簡単にクラッシュできると思います。
LPSTR CharMoveNext(LPSTR szString)
{
if (szString == 0 || *szString == 0)
return 0;
if ( (szString[0] & 0x80) == 0x00)
return szString + 1;
else if ( (szString[0] & 0xE0) == 0xC0)
return szString + 2;
else if ( (szString[0] & 0xF0) == 0xE0)
return szString + 3;
else if ( (szString[0] & 0xF8) == 0xF0)
return szString + 4;
else
return szString +1;
}