UTF16转换失败,使用utfcpp

时间:2014-01-17 21:38:40

标签: c++ utfcpp

我在下面的代码中写了一些代码,使用utfcpp将utf16编码文件转换为utf8字符串。

我认为我必须使用它不正确,因为结果不会改变。 utf8content变量的每个字符都出现空字符(\0),就像我放入其中的uft16一样。

//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的方式出了什么问题?是否有一些我做错了的类型转换?

我的内容是UTF16编码的xml文件。它似乎在第一个空字符处截断结果。

2 个答案:

答案 0 :(得分:2)

std::ifstream以8位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!
}

答案 1 :(得分:1)

问题在于您正在阅读文件:

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

这一行采用char迭代器并使用它一次填充一个字节的向量。你实际上是在逐个转换每个字节,而不是一次读取两个字节。

这会将每个UTF-16实体分成两部分,对于你的大部分输入,这两部分中的一部分将是一个空字节。