Question

J'ai une chaîne multi-octets contenant un mélange de caractères japonais et latins. J'essaie de copier des parties de cette chaîne dans un emplacement de mémoire distinct. Comme il s'agit d'une chaîne multi-octets, certains caractères utilisent un octet et d'autres, deux. Lors de la copie de parties de la chaîne, je ne dois pas copier "moitié". caractères japonais. Pour pouvoir le faire correctement, je dois pouvoir déterminer où commencent et se terminent les caractères de la chaîne multi-octets.

Par exemple, si la chaîne contient 3 caractères nécessitant [2 octets] [2 octets] [1 octet], je dois copier 2, 4 ou 5 octets vers l'autre emplacement et non 3, car si j'étais copier 3 Je ne copierais que la moitié du deuxième caractère.

Pour savoir où commence et finit les caractères de la chaîne multi-octets, j'essaie d'utiliser la fonction API Windows CharNext et CharNextExA, mais sans succès. Lorsque j'utilise ces fonctions, elles parcourent ma chaîne, un octet à la fois, plutôt qu'un caractère à la fois. Selon MSDN, CharNext est supposé La fonction CharNext récupère un pointeur sur le caractère suivant d'une chaîne. .

Voici du code pour illustrer ce problème:

#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);
   }
}

(veuillez ignorer la fuite de mémoire et l'échec de la vérification des erreurs.)

Maintenant, dans l'exemple ci-dessus, je m'attendrais à ce que characterCount devienne 6, car c'est le nombre de caractères de la chaîne asiatique. Au lieu de cela, characterCount devient 18 car mbString contient 18 caractères:

門阜陀阿阻附

Je ne comprends pas comment cela est censé fonctionner. Comment est-ce que CharNext est censé savoir si " é– € é " dans la chaîne est une version codée d'un caractère japonais, ou en fait les caractères é - € et é?

Quelques notes:

  • J'ai lu sur le blog de Joels ce que tous les développeurs doivent savoir sur Unicode. Cependant, j’ai peut-être mal compris quelque chose.
  • Si tout ce que je voulais, c'était compter les caractères, je pouvais les compter directement dans la chaîne asiatique. N'oubliez pas que mon objectif réel est de copier des parties de la chaîne multi-octets dans un emplacement distinct. L'emplacement distinct prend uniquement en charge plusieurs octets, et non widechar.
  • Si je reconvertis le contenu de mbString en caractères larges à l’aide de MultiByteToWideChar, j’obtiens la chaîne correcte (? ?), ce qui indique qu’il n’ya aucun problème avec mbString.

EDIT: Apparemment, les fonctions CharNext ne prennent pas en charge UTF-8 mais Microsoft a oublié de le documenter. J'ai jeté / copié ensemble ma propre routine que je n'utiliserai pas et qui a besoin d'être améliorée. J'imagine que c'est facile à graver.

  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;
  }
Était-ce utile?

La solution

Voici une très bonne explication de ce qui se passe ici sur le blog : CharNextExA est-il défectueux? . En bref, CharNext n’est pas conçu pour fonctionner avec les chaînes UTF8.

Autres conseils

Autant que je sache (Google et l'expérimentation), CharNextExA ne fonctionne pas avec UTF-8, mais prend en charge les codages multi-octets qui utilisent des paires d'octets piste / piste ou un octet plus courtes.

UTF-8 est un encodage assez régulier, il y a beaucoup de bibliothèques qui feront ce que vous voulez, mais il est également assez facile de lancer votre propre.

Jetez un coup d'œil ici unicode.org , en particulier un tableau 3-7 pour les formes de séquence valides.

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.
    // ...
}

Etant donné que CharNextExA ne Si vous n’utilisez pas UTF-8 , vous pouvez l’analyser vous-même. Passez simplement sur les caractères qui ont 10 dans les deux bits supérieurs. Vous pouvez voir le motif dans la définition de UTF-8: http://en.wikipedia.org / wiki / Utf-8

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

Ce n’est pas une réponse directe à votre question, mais vous pouvez trouver le tutoriel suivant utile, je l’ai certainement fait. En fait, les informations fournies ici sont suffisantes pour que vous puissiez facilement parcourir la chaîne de plusieurs octets:

Didacticiel complet sur les chaînes

Essayez d’utiliser 932 pour la page de code. Je ne pense pas que CP_UTF8 soit une vraie page de codes et ne fonctionne que pour WideCharToMultibyte () et vice-versa. Vous pouvez également essayer isleadByte (), mais cela nécessite de définir les paramètres régionaux correctement ou de définir correctement la page de codes par défaut. J'ai utilisé avec succès IsDBCSLeadByteEx (), mais jamais avec CP_UTF8.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top