Windows APIでCharNextを適切に使用するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1235798

  •  22-07-2019
  •  | 
  •  

質問

日本語とラテン文字が混在したマルチバイト文字列があります。この文字列の一部を別のメモリの場所にコピーしようとしています。マルチバイト文字列であるため、一部の文字は1バイトを使用し、他の文字は2バイトを使用します。文字列の一部をコピーするとき、「半分」をコピーしてはいけません。日本語のキャラクター。これを適切に行うには、マルチバイト文字列の文字の開始位置と終了位置を特定できる必要があります。

例として、文字列に[2バイト] [2バイト] [1バイト]を必要とする3文字が含まれている場合、2バイト、4バイト、または5バイトを3ではなく他の場所にコピーする必要があります。コピー3 2番目の文字の半分だけをコピーします。

マルチバイト文字列の文字の開始位置と終了位置を把握するために、Windows API関数CharNextとCharNextExAを使用しようとしていますが、運はありません。これらの関数を使用すると、一度に1文字ではなく、一度に1バイトずつ文字列をナビゲートします。 MSDNによると、CharNextは 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は、&quot;&#233;&#8211;&#8364;&#233;&quot;文字列内は日本語文字のエンコードされたバージョン、または実際には文字&#233;です。 &#8211; &#8364;および&#233;?

注意事項:

  • すべての開発者がUnicodeについて知っておくべきことについて、Joelsのブログ投稿を読みました。私はその中に何かを誤解したかもしれません。
  • 文字列を数えるだけでしたい場合は、アジア文字列の文字列を直接数えます。私の本当の目標は、マルチバイト文字列の一部を別の場所にコピーすることです。別の場所はマルチバイトのみをサポートし、ワイド文字はサポートしません。
  • MultiByteToWideCharを使用してmbStringのコンテンツをワイド文字に変換すると、正しい文字列(&#38272;&#38428;&#38464;&#38463;&#38459;&#38468;)が得られます。 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;
  }
役に立ちましたか?

解決

Sorting it All Outブログで、ここで何が行われているのか、本当に良い説明があります。 CharNextExAが壊れていますか。要するに、CharNextはUTF8文字列で動作するようには設計されていません。

他のヒント

私が判断できる限り(グーグルと実験)、 CharNextExA は実際にはUTF-8では動作せず、短いリード/トレイルバイトペアまたはシングルバイト文字を使用するマルチバイトエンコーディングのみをサポートします。

UTF-8はかなり規則的なエンコーディングであり、必要なことを行うライブラリがたくさんありますが、独自のロールを作成することもかなり簡単です。

こちら unicode.org 、特に表をご覧ください有効なシーケンス形式の場合は3-7。

const char* NextUtf8( const char* in )
{
    if( in == NULL || *in == '\0' )
        return in;

    unsigned char uc = static_cast<unsigned char>(*in);

    if( uc < 0x80 )
    {
        return in + 1;
    }
    else if( uc < 0xc2 )
    {
         // throw error? invalid lead byte
    }
    else if( uc < 0xe0 )
    {
        // check in[1] for validity( 0x80 .. 0xBF )
        return in + 2;
    }
    else if( uc < 0xe1 )
    {
        // check in[1] for validity( 0xA0 .. 0xBF )
        // check in[2] for validity( 0x80 .. 0xBF )
        return in + 3;
    }
    else // ... etc.
    // ...
}

CharNextExAが「 UTF-8で動作する場合、自分で解析できます。上位2ビットに10が含まれる文字をスキップします。 UTF-8の定義でパターンを見ることができます: http://en.wikipedia.org / wiki / Utf-8

LPSTR CharMoveNext(LPSTR szString)
{
    ++szString;
    while ((*szString & 0xc0) == 0x80)
        ++szString;
    return szString;
}

これはあなたの質問に対する直接的な答えではありませんが、次のチュートリアルが役立つと思うかもしれません。実際、ここで提供される情報は、マルチバイト文字列を自分で簡単にたどることができるほど十分です:

完全な文字列チュートリアル

コードページに932を使用してみてください。 CP_UTF8は実際のコードページとは思わず、WideCharToMultibyte()以降でのみ機能する可能性があります。 isleadByte()を試すこともできますが、それにはロケールを正しく設定するか、デフォルトのコードページを正しく設定する必要があります。 IsDBCSLeadByteEx()を正常に使用しましたが、CP_UTF8では使用しませんでした。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top