문제

일본어와 라틴 문자가 혼합된 멀티바이트 문자열이 있습니다.이 문자열의 일부를 별도의 메모리 위치에 복사하려고 합니다.멀티바이트 문자열이므로 일부 문자는 1바이트를 사용하고 다른 문자는 2바이트를 사용합니다.문자열의 일부를 복사할 때 "절반" 일본어 문자를 복사하면 안 됩니다.이 작업을 제대로 수행하려면 멀티바이트 문자열 문자의 시작과 끝 위치를 확인할 수 있어야 합니다.

예를 들어, 문자열에 [2바이트][2바이트][1바이트]가 필요한 3개의 문자가 포함된 경우 3바이트가 아닌 2, 4 또는 5바이트를 다른 위치에 복사해야 합니다. 두 번째 문자의 절반만 복사합니다.

멀티바이트 문자열 문자의 시작과 끝 위치를 파악하기 위해 Windows API 함수 CharNext 및 CharNextExA를 사용하려고 시도했지만 운이 없었습니다.이 함수를 사용하면 한 번에 한 문자가 아닌 한 번에 한 바이트씩 문자열을 탐색합니다.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);
   }
}

(메모리 누수 및 오류 검사 실패를 무시하십시오.)

이제 위의 예에서는 문자 개수가 6이 될 것으로 예상합니다. 이는 아시아 문자열의 문자 수이기 때문입니다.그러나 대신 mbString에 18개의 문자가 포함되어 있으므로 CharacterCount는 18이 됩니다.

門阜陀阿阻附

어떻게 작동하는지 이해가 안 돼요.CharNext는 문자열의 "é–€é"가 일본어 문자의 인코딩된 버전인지 아니면 실제로 문자 é – € 및 é인지 어떻게 알 수 있습니까?

몇 가지 참고사항:

  • 모든 개발자가 유니코드에 대해 알아야 할 사항에 대한 Joels 블로그 게시물을 읽었습니다.그래도 뭔가 오해했을 수도 있습니다.
  • 내가 원하는 것이 문자 수를 세는 것뿐이었다면 아시아 문자열의 문자 수를 직접 셀 수 있었습니다.내 실제 목표는 멀티바이트 문자열의 일부를 별도의 위치에 복사하는 것임을 명심하세요.별도의 위치는 widechar가 아닌 멀티바이트만 지원합니다.
  • 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;
  }
도움이 되었습니까?

해결책

여기에서 무슨 일이 일어나고 있는지에 대한 정말 좋은 설명이 있습니다. 모두 정리하기 블로그: 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