Pergunta

I têm uma cadeia de multi-byte contendo uma mistura de japonês e caracteres latino. Eu estou tentando copiar partes desta cadeia para um local de memória separado. Desde que é uma string multi-byte, alguns dos personagens usa um byte e outros personagens usa dois. Ao copiar partes da cadeia, não deve copiar "meia" caracteres japoneses. Para ser capaz de fazer isso corretamente, eu preciso ser capaz de determinar onde nos multi-byte cordas personagens começa e termina.

Como um exemplo, se a cadeia contém 3 caracteres que requer [2 bytes] [2 bytes] [1 byte], eu deve copiar ou 2, 4 ou 5 bytes para outro local e não 3, uma vez que se fosse copiando 3 gostaria de copiar apenas metade do segundo personagem.

Para descobrir onde nos multi-byte cordas personagens começa e termina, eu estou tentando usar a função de API do Windows CharNext e CharNextExA mas sem sorte. Quando eu usar essas funções, eles navegam através da minha corda um byte de cada vez, em vez de um carácter de cada vez. De acordo com MSDN, CharNext é suposto A função CharNext recupera um ponteiro para o próximo caractere em uma string. .

Aqui está algum código para ilustrar este problema:

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

(ignore vazamento de memória e incapacidade de fazer a verificação de erros.)

Agora, no exemplo acima, eu esperaria que characterCount torna-se 6, já que é o número de caracteres na seqüência asiático. Mas em vez disso, torna-se characterCount 18 porque mbstring contém 18 caracteres:

門阜陀阿阻附

Eu não entendo como é suposto trabalho. Como é CharNext suposto saber se "é- € E" na cadeia é uma versão codificada de um personagem japonês, ou de facto os personagens e -? € e E

Algumas notas:

  • Eu li Joels blog sobre o que cada desenvolvedor precisa de saber sobre Unicode. Talvez eu tenha entendido mal algo nele embora.
  • Se tudo que eu queria fazer era contar os caracteres, eu poderia contar os caracteres na cadeia asiático diretamente. Tenha em mente que o meu verdadeiro objetivo é copiar partes da cadeia multi-byte para um local separado. O local separado só suporta multi-byte, não widechar.
  • Se eu converter o conteúdo do mbstring volta ao largo de char usando MultiByteToWideChar, fico com a seqüência correta (? ? ? ? ? ?), o que indica que não há nada de errado com mbstring.

EDIT: Aparentemente as funções CharNext não suporta UTF-8 mas a Microsoft esqueceu de documentar isso. Eu joguei / copiedpasted juntos minha própria rotina, que eu não vou usar e que precisa melhorar. Eu estou supondo que é facilmente crashable.

  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;
  }
Foi útil?

Solução

Aqui está uma explicação muito boa do que está acontecendo aqui no classificando-All Out blogue : Is CharNextExA quebrado ?. Em suma, CharNext não foi projetado para trabalho com cordas UTF8.

Outras dicas

Tanto quanto eu posso determinar (google e experimentação), CharNextExA na verdade não funciona com UTF-8, a codificação multibyte com suporte apenas que usam pares de bytes chumbo / trilha mais curtos ou caracteres de byte único.

UTF-8 é uma codificação bastante regular, há um grande número de bibliotecas que irá fazer o que quiser, mas também é bastante fácil de rolar o seu próprio.

Tenha um olhar aqui unicode.org , especialmente mesa 3-7 para formas de sequências válidas.

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

Dado que CharNextExA doesn' t trabalho com UTF-8 , você pode analisá-lo sozinho. Apenas saltar sobre os personagens que têm 10 nos dois primeiros pedaços. Você pode ver o padrão na definição de UTF-8: http://en.wikipedia.org / wiki / UTF-8

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

Esta não é uma resposta directa à sua pergunta, mas você pode encontrar o seguinte útil tutorial, eu certamente o fez. Na verdade, a informação fornecida aqui é o suficiente para que você deve ser capaz de atravessar a corda multi-byte-se com facilidade:

cadeia completa Tutorial

Tente usar 932 para a página de código. Eu não acho que CP_UTF8 é uma verdadeira página de código, e isso só pode trabalhar para WideCharToMultiByte () e volta. Você também pode tentar isleadByte (), mas que exige quer definir o local corretamente, ou definir a página de códigos padrão corretamente. Eu tenho usado com sucesso IsDBCSLeadByteEx (), mas nunca com CP_UTF8.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top