Проблемное определение явно указывает, что 8-разрядная кодировка символов является UTF-8. Это делает это тривиальной проблемой; все, чего требуется, является небольшим битовым жонглированием для преобразования от одной спецификации UTF до другого.
Только посмотрели на кодировку на этих страницах Wikipedia для UTF-8, UTF-16, и UTF-32.
принцип прост - проходят вход и собирают 32-разрядную кодовую точку Unicode согласно одной спецификации UTF, затем испускают кодовую точку согласно другой спецификации. Для отдельных кодовых точек не нужен никакой перевод, как требовался бы с любой другой кодировкой символов; это - то, что делает это простой проблемой.
Вот быстрая реализация wchar_t
к преобразованию UTF-8 и наоборот. Это предполагает, что вход уже правильно кодируется - старая поговорка "Мусор в, мусор" применяется здесь. Я полагаю, что проверка кодирования лучше всего сделана как отдельный шаг.
std::string wchar_to_UTF8(const wchar_t * in)
{
std::string out;
unsigned int codepoint = 0;
for (in; *in != 0; ++in)
{
if (*in >= 0xd800 && *in <= 0xdbff)
codepoint = ((*in - 0xd800) << 10) + 0x10000;
else
{
if (*in >= 0xdc00 && *in <= 0xdfff)
codepoint |= *in - 0xdc00;
else
codepoint = *in;
if (codepoint <= 0x7f)
out.append(1, static_cast<char>(codepoint));
else if (codepoint <= 0x7ff)
{
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else if (codepoint <= 0xffff)
{
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else
{
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
codepoint = 0;
}
}
return out;
}
вышеупомянутый код работает и на UTF-16 и на вход UTF-32, просто потому что диапазон d800
до dfff
является недопустимыми кодовыми точками; они указывают, что Вы декодируете UTF-16. Если Вы знаете, что wchar_t
32 бита тогда, Вы могли удалить некоторый код для оптимизации функции.
std::wstring UTF8_to_wchar(const char * in)
{
std::wstring out;
unsigned int codepoint;
while (*in != 0)
{
unsigned char ch = static_cast<unsigned char>(*in);
if (ch <= 0x7f)
codepoint = ch;
else if (ch <= 0xbf)
codepoint = (codepoint << 6) | (ch & 0x3f);
else if (ch <= 0xdf)
codepoint = ch & 0x1f;
else if (ch <= 0xef)
codepoint = ch & 0x0f;
else
codepoint = ch & 0x07;
++in;
if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
{
if (sizeof(wchar_t) > 2)
out.append(1, static_cast<wchar_t>(codepoint));
else if (codepoint > 0xffff)
{
out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
}
else if (codepoint < 0xd800 || codepoint >= 0xe000)
out.append(1, static_cast<wchar_t>(codepoint));
}
}
return out;
}
Снова, если Вы знаете, что wchar_t
32 бита, Вы могли удалить некоторый код из этой функции, но в этом случае это не должно иметь никакого значения. Выражение sizeof(wchar_t) > 2
известно во время компиляции, таким образом, любой достойный компилятор распознает мертвый код и удалит его.
Можно извлечь utf8_codecvt_facet
от библиотека сериализации Повышения .
Их пример использования:
typedef wchar_t ucs4_t;
std::locale old_locale;
std::locale utf8_locale(old_locale,new utf8_codecvt_facet<ucs4_t>);
// Set a New global locale
std::locale::global(utf8_locale);
// Send the UCS-4 data out, converting to UTF-8
{
std::wofstream ofs("data.ucd");
ofs.imbue(utf8_locale);
std::copy(ucs4_data.begin(),ucs4_data.end(),
std::ostream_iterator<ucs4_t,ucs4_t>(ofs));
}
// Read the UTF-8 data back in, converting to UCS-4 on the way in
std::vector<ucs4_t> from_file;
{
std::wifstream ifs("data.ucd");
ifs.imbue(utf8_locale);
ucs4_t item = 0;
while (ifs >> item) from_file.push_back(item);
}
Ищут utf8_codecvt_facet.hpp
и utf8_codecvt_facet.cpp
файлы в источниках повышения.
Существует несколько способов сделать это, но результаты зависят от того, что кодировки символов находятся в string
и wstring
переменные.
, Если Вы знаете эти string
, ASCII, можно просто использовать wstring
конструктор итератора:
string s = "This is surely ASCII.";
wstring w(s.begin(), s.end());
, Если Ваш string
имеет некоторое другое кодирование, однако, Вы получите очень плохие результаты. Если кодирование является Unicode, Вы могли бы смотреть на проект ICU, который обеспечивает межплатформенный набор библиотек, которые преобразовывают в и от всех видов кодировки Unicode.
, Если Ваш string
содержит символы в кодовой странице, то может $DEITY щадить Вашу душу.
Можно использовать codecvt
фасет локали . Существует определенная определенная специализация, codecvt<wchar_t, char, mbstate_t>
, который может быть полезен для Вас, хотя, поведение этого является определенным для системы, и не гарантирует преобразование в UTF-8 всегда.
Я не думаю, что существует портативный способ сделать это. C++ не знает кодирование своих многобайтовых символов.
Как предложенный Chris, Ваш лучший выбор состоит в том, чтобы играть с codecvt.