Как преобразовать строку Unicode в строку utf-8 или utf-16? Мой проект VS2005 использует набор символов Unicode, а sqlite в cpp предоставляет
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
для открытия папки. Как преобразовать строку, CString или wstring в кодировку UTF-8 или UTF-16?
Огромное спасибо!





Используйте функцию WideCharToMultiByte. Укажите CP_UTF8 для параметра CodePage.
CHAR buf[256]; // or whatever
WideCharToMultiByte(
CP_UTF8,
0,
StringToConvert, // the string you have
-1, // length of the string - set -1 to indicate it is null terminated
buf, // output
__countof(buf), // size of the buffer in bytes - if you leave it zero the return value is the length required for the output buffer
NULL,
NULL
);
Кроме того, кодировка по умолчанию для приложений Unicode в Windows - UTF-16LE, поэтому вам может не понадобиться выполнять какой-либо перевод и просто используйте вторую версию sqlite3_open16.
Я не согласен: вы показываете, как конвертировать из UTF16 в UTF8. Это не требование OP, поскольку, похоже, для широких строк символов доступна функция: sqlite3_open16 (). IMO, правильный ответ: используйте sqlite3_open16 ().
@Chris, поэтому я сказал "или что-то еще" и добавил комментарий к размеру выходного буфера - я не хотел слишком усложнять ситуацию
utf-8 и utf-16 являются кодировками символов "юникод". Вероятно, вы говорите о utf-32, кодировке символов фиксированного размера. Может быть, ищу
"Convert utf-32 into utf-8 or utf-16"
предоставляет вам некоторые результаты или другие статьи по этому поводу.
Все строковые типы C++ нейтральны по кодировке. Они просто выбирают ширину символа и не делают никаких дополнительных предположений. Wstring использует 16-битные символы в Windows, что примерно соответствует utf-16, но все равно зависит от того, что вы храните в потоке. Wstring никоим образом не требует, чтобы данные, которые вы в него вводили, были действительными utf16. Windows использует utf16, когда определен UNICODE, поэтому, скорее всего, ваши строки уже являются utf16, и вам не нужно ничего делать.
Некоторые другие предложили использовать функцию WideCharToMultiByte, которая является (одним из) способов преобразования utf16 в utf8. Но поскольку sqlite может обрабатывать utf16, в этом нет необходимости.
Короткий ответ:
При использовании строк Unicode, таких как CString или wstring, преобразование не требуется. Используйте sqlite3_open16 ().
Вам нужно будет убедиться, что вы передаете указатель WCHAR (приведенный к void *. Кажется хромым! Даже если эта библиотека является кросс-платформенной, я думаю, они могли бы определить широкий тип char, который зависит от платформы и менее недружелюбен, чем void *) к API. Например, для CString: (void*)(LPCWSTR)strFilename
Более длинный ответ:
У вас нет строки Unicode, которую вы хотите преобразовать в UTF8 или UTF16. У вас есть строка Unicode, представленная в вашей программе с использованием заданной кодировки: Unicode не является двоичным представлением как таковым. Кодировки говорят, как кодовые точки Unicode (числовые значения) представлены в памяти (двоичная структура числа). UTF8 и UTF16 - наиболее широко используемые кодировки. Хотя они очень разные.
Когда в проекте VS указано «Кодировка Unicode», это фактически означает «символы в кодировке UTF16». Следовательно, вы можете использовать sqlite3_open16 () напрямую. Конверсия не требуется. Символы хранятся в типе WCHAR (в отличие от char), который занимает 16 бит (откат для стандартного типа C wchar_t, который занимает 16 бит в Win32. На других платформах может быть иначе. Спасибо за исправление, Checkers).
Есть еще одна деталь, на которую вы, возможно, захотите обратить внимание: UTF16 существует в двух вариантах: Big Endian и Little Endian. Это порядок байтов этих 16 бит. Прототип функции, который вы даете для UTF16, не говорит, какой порядок используется. Но вы вполне уверены, что sqlite использует тот же порядок байтов, что и Windows (Little Endian IIRC. Я знаю порядок, но у меня всегда были проблемы с именами :-)).
Обновлено: ответ на комментарий Checkers:
UTF16 использует 16 бит кодовые единицы. В Win32 (и Только в Win32) для такого хранилища используется wchar_t. Хитрость в том, что для некоторых символов Unicode требуется последовательность из 2 таких 16-битных кодовых единиц. Их называют суррогатными парами.
Точно так же UTF8 представляет 1 символ с использованием последовательности от 1 до 4 байтов. Тем не менее, UTF8 используется с типом char.
Нет нет нет! sqlite3_open16 () использует аргумент void *, потому что он указан как UTF16, НЕТ wchar_t, который имеет разный размер на разных платформах и может быть или не быть UTF16 (т.е. glibc имеет 4-байтовый wchar_t).
Шашки: см. Мой ответ как ИЗМЕНИТЬ здесь выше
Да, мне известно о представлении UTF16. Но вы не можете предполагать, что внутреннее представление wchar_t одинаково на всех платформах, это не так.
«Стандарт ISO C90, в котором был введен wchar_t, не говорит ничего конкретного о представлении. Он требует только, чтобы этот тип мог хранить все элементы базового набора символов» gnu.org/software/libtool/manual/libc/Extended-Char-Intro.htm l
Например, в моей системе, где sizeof (wchar_t) == 4, L "aaa" компилируется как 61 00 00 00 61 00 00 00 61 00 00 00 (UTF32-LE)
В ПОРЯДКЕ. Ты прав. Я исправился. Теперь, поддерживает ли ваша платформа VS2005, как указано в OP?
На самом деле, я бы сказал, что UTF16 использует 16-битные коды (не символы), так же как UTF8 использует 8-битные (октетные) коды. Код символа Юникода (до 20 бит) потребует 1 код UTF16 для часто используемых символов, но для других - два (называемых суррогатной парой).
оркмид, ты прав. Я использовал слово «характер» при принятии его типа программирования, что могло ввести в заблуждение.
По-прежнему может потребоваться преобразование: не гарантируется, что wchar_t будет 16-битным, а в системах, отличных от Windows, скорее всего, будет 32-битным. Это может не иметь отношения к плакату, но может быть очень важной деталью для других.
@orcmid Срок - кодовая единица. Единица подразумевает, что это наименьший строительный блок: может потребоваться один или несколько.
Самый простой способ сделать это - использовать CStringA. Класс CString является typedef для CStringA (версия ASCII) или CStringW (версия с расширенными символами). Оба этих класса имеют конструкторы для преобразования строковых типов. Обычно я использую:
sqlite3_open(CStringA(L"MyWideCharFileName"), ...);
Я бы не рекомендовал фиксированный буфер; вместо этого используйте динамически выделяемый буфер (например, std :: vector), расширяясь по мере необходимости (когда WideCharToMultiByte сообщает вам, что ваша строка слишком мала).