Windows API에서 CharNext를 어떻게 올바르게 사용합니까?
문제
일본어와 라틴 문자가 혼합된 멀티바이트 문자열이 있습니다.이 문자열의 일부를 별도의 메모리 위치에 복사하려고 합니다.멀티바이트 문자열이므로 일부 문자는 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에서는 사용한 적이 없습니다.