У меня есть многобайтовая строка, содержащая смесь японских и латинских символов. Я пытаюсь скопировать части этой строки в отдельную область памяти. Поскольку это многобайтовая строка, некоторые символы используют один байт, а другие - два. При копировании частей строки я не должен копировать «наполовину» японские символы. Чтобы быть в состоянии сделать это правильно, мне нужно иметь возможность определить, где в многобайтовой строке символы начинаются и заканчиваются.
Например, если строка содержит 3 символа, для которых требуется [2 байта] [2 байта] [1 байт], я должен скопировать 2, 4 или 5 байтов в другое место, а не 3, так как если бы я был копирование 3 Я бы скопировал только половину второго символа.
Чтобы выяснить, где в многобайтовой строке начинаются и заканчиваются символы, я пытаюсь использовать функции API-интерфейса Windows 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, поскольку это количество символов в азиатской строке. Но вместо этого CharacterCount становится 18, потому что mbString содержит 18 символов:
門阜陀阿阻附
Я не понимаю, как это должно работать. Как CharNext должен знать, является ли «é– € é» в строке кодированной версией японского символа, или на самом деле символы é - € и é?
Некоторые заметки:
- Я прочитал в блоге Joels о том, что каждый разработчик должен знать о Unicode. Возможно, я что-то неправильно понял в этом.
- Если бы я только хотел посчитать символы, я мог бы посчитать символы в азиатской строке напрямую. Имейте в виду, что моей настоящей целью является копирование частей многобайтовой строки в отдельное место. Отдельное расположение поддерживает только многобайтовые, а не широкие символы.
- Если я преобразую содержимое mbString обратно в широкий символ, используя MultiByteToWideChar, я получу правильную строку (門 阜 陀 阿 阻 附), которая указывает, что с mbString все в порядке.
EDIT:
Очевидно, что функции 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;
}