Сбой преобразования UTF16 с помощью utfcpp

У меня есть этот фрагмент кода ниже, который я написал, который использует utfcpp конвертировать из файла в кодировке utf16 в строку utf8.

Я думаю, что я должен использовать это неправильно, потому что результат не меняется. utf8content переменная выходит с нулевыми символами (\0) любой другой персонаж точно такой же, как тот, который я в него вложил.

//get file content
string utf8content;
std::ifstream ifs(path);
vector<unsigned short> utf16line((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

//convert
if(!utf8::is_valid(utf16line.begin(), utf16line.end())){
utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8content));
}

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

От checked.h вот метод добавления (строка 106). Это называется utf16to8 (строка 202). Обратите внимание, что я добавил первую часть if, чтобы она пропускала нулевые символы в попытке решить проблему.

template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);

if(cp < 0x01)                 //<===I added this line and..
*(result++);              //<===I added this line
else if (cp < 0x80)                        // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) {                // two octets
*(result++) = static_cast<uint8_t>((cp >> 6)            | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
}
else if (cp < 0x10000) {              // three octets
*(result++) = static_cast<uint8_t>((cp >> 12)           | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
}
else {                                // four octets
*(result++) = static_cast<uint8_t>((cp >> 18)           | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)  | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
}
return result;
}

Однако я не могу себе представить, что это решение, просто удаляющее нулевые символы из строки, и почему библиотека не нашла это? Ясно, что я делаю что-то не так.

Итак, мой вопрос: что плохого в том, как я реализую свой utfcpp в первом бите кода? Есть ли какое-то преобразование типов, которое я сделал неправильно?

Мое содержимое представляет собой XML-файл в кодировке UTF16. Кажется, чтобы усечь результаты в первом нулевом символе.

2

Решение

std::ifstream читает файл в 8bit char единицы. UTF-16 использует вместо этого 16-битные блоки. Так что, если вы хотите прочитать файл и заполнить свой вектор надлежащими единицами UTF-16, используйте std::wifstream вместо (или std::basic_ifstream<char16_t> или эквивалент, если wchar_t не 16-битный на вашей платформе).

И не звони utf8::is_valid() Вот. Он ожидает ввода UTF-8, но вместо этого у вас есть ввод UTF-16.

Если sizeof(wchar_t) это 2:

std::wifstream ifs(path);
std::istreambuf_iterator<wchar_t> ifs_begin(ifs), ifs_end;
std::wstring utf16content(ifs_begin, ifs_end);
std::string utf8content;

try {
utf8::utf16to8(utf16content.begin(), utf16content.end(), std::back_inserter(utf8content));
}
catch (const utf8::invalid_utf16 &) {
// bad UTF-16 data!
}

Иначе:

// if char16_t is not available, use unit16_t or unsigned short instead

std::basic_ifstream<char16_t> ifs(path);
std::istreambuf_iterator<char16_t> ifs_begin(ifs), ifs_end;
std::basic_string<char16_t> utf16content(ifs_begin, ifs_end);
std::string utf8content;

try {
utf8::utf16to8(utf16content.begin(), utf16content.end(), std::back_inserter(utf8content));
}
catch (const utf8::invalid_utf16 &) {
// bad UTF-16 data!
}
2

Другие решения

Проблема в том, где вы читаете файл:

vector<unsigned short> utf16line((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

Эта линия принимает char итератор и использовать его для заполнения вектора по одному байту за раз. Вы по сути приводите каждый байт вместо чтения двух байтов за раз.

Это разбивает каждую сущность UTF-16 на две части, и для большей части вашего ввода одна из этих двух частей будет нулевым байтом.

1

По вопросам рекламы [email protected]