Как преобразовать строку Unicode в строку utf-8 или utf-16?

Как преобразовать строку 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?

Огромное спасибо!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
34 353
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Используйте функцию 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.

Я бы не рекомендовал фиксированный буфер; вместо этого используйте динамически выделяемый буфер (например, std :: vector), расширяясь по мере необходимости (когда WideCharToMultiByte сообщает вам, что ваша строка слишком мала).

Chris Jester-Young 11.11.2008 12:06

Я не согласен: вы показываете, как конвертировать из UTF16 в UTF8. Это не требование OP, поскольку, похоже, для широких строк символов доступна функция: sqlite3_open16 (). IMO, правильный ответ: используйте sqlite3_open16 ().

Serge Wautier 11.11.2008 12:41

@Chris, поэтому я сказал "или что-то еще" и добавил комментарий к размеру выходного буфера - я не хотел слишком усложнять ситуацию

1800 INFORMATION 12.11.2008 09:23

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).

Alex B 11.11.2008 12:49

Шашки: см. Мой ответ как ИЗМЕНИТЬ здесь выше

Serge Wautier 11.11.2008 13:45

Да, мне известно о представлении UTF16. Но вы не можете предполагать, что внутреннее представление wchar_t одинаково на всех платформах, это не так.

Alex B 11.11.2008 14:05

«Стандарт ISO C90, в котором был введен wchar_t, не говорит ничего конкретного о представлении. Он требует только, чтобы этот тип мог хранить все элементы базового набора символов» gnu.org/software/libtool/manual/libc/Extended-Char-Intro.htm‌ l

Alex B 11.11.2008 14:06

Например, в моей системе, где sizeof (wchar_t) == 4, L "aaa" компилируется как 61 00 00 00 61 00 00 00 61 00 00 00 (UTF32-LE)

Alex B 11.11.2008 14:08

В ПОРЯДКЕ. Ты прав. Я исправился. Теперь, поддерживает ли ваша платформа VS2005, как указано в OP?

Serge Wautier 11.11.2008 17:27

На самом деле, я бы сказал, что UTF16 использует 16-битные коды (не символы), так же как UTF8 использует 8-битные (октетные) коды. Код символа Юникода (до 20 бит) потребует 1 код UTF16 для часто используемых символов, но для других - два (называемых суррогатной парой).

orcmid 11.11.2008 23:18

оркмид, ты прав. Я использовал слово «характер» при принятии его типа программирования, что могло ввести в заблуждение.

Serge Wautier 11.11.2008 23:27

По-прежнему может потребоваться преобразование: не гарантируется, что wchar_t будет 16-битным, а в системах, отличных от Windows, скорее всего, будет 32-битным. Это может не иметь отношения к плакату, но может быть очень важной деталью для других.

Wichert Akkerman 12.06.2011 01:56

@orcmid Срок - кодовая единица. Единица подразумевает, что это наименьший строительный блок: может потребоваться один или несколько.

Tom Blodget 23.08.2014 03:33

Самый простой способ сделать это - использовать CStringA. Класс CString является typedef для CStringA (версия ASCII) или CStringW (версия с расширенными символами). Оба этих класса имеют конструкторы для преобразования строковых типов. Обычно я использую:

sqlite3_open(CStringA(L"MyWideCharFileName"), ...);

Другие вопросы по теме