将字符串从UTF-8转换为ISO-8859-1

7

我正在尝试将UTF-8 string转换为ISO-8859-1 char*以在旧代码中使用。我唯一看到的方法是使用iconv

我肯定更喜欢完全基于string的C++解决方案,然后只需在结果字符串上调用.c_str()

我该怎么做?如果可能,请提供代码示例。如果您只知道使用iconv作为唯一解决方案,那也可以。


这听起来像是一个潜在的大项目 - 而且正是像iconv这样的库所擅长的。做正确的事有什么问题吗? - Carl Norum
如果iconv是唯一可用的方法,我可以使用它。这绝对不是最优雅的C++解决方案。像s.toEncoding("ISO-8859-1")这样的方式会更加优雅。我的观点是,即使我在使用iconv,我也不清楚如何将库与“string”输入一起使用。 - Chris Redford
不确定,但可能有帮助:http://www.openldap.org/lists/openldap-devel/200304/msg00123.html - gerbit
3个回答

12

我打算修改我的代码来自另一个答案,以实现Alf的建议。

std::string UTF8toISO8859_1(const char * in)
{
    std::string out;
    if (in == NULL)
        return 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 (codepoint <= 255)
            {
                out.append(1, static_cast<char>(codepoint));
            }
            else
            {
                // do whatever you want for out-of-bounds characters
            }
        }
    }
    return out;
}

无效的UTF-8输入会导致字符丢失。


实际上,我有一个UTF-8编码的字符串。如果你能将其转换为字符串,那就太完美了。 - Chris Redford
@ChrisRedford,只需使用 mystr.c_str() 进行调用。我喜欢使用 const char * 输入,因为它更加灵活。 - Mark Ransom
1
由于输入来自std::string,只需将const char * in替换为const std::string&in,然后创建一个本地的char*变量,该变量被分配为in.c_str()以供在循环中使用,并使用in.size()作为循环计数器,而不是*in != 0。或者使用in.begin()in.end()迭代器。 - Remy Lebeau
@GustavoRodríguez 这很容易做到,因为Unicode采用了Latin-1字符集作为其前256个代码点,无需翻译。 - Mark Ransom
也许使用 char8_t 会更好。 - Константин Ван
显示剩余2条评论

6

首先将UTF-8转换为32位Unicode。

然后保留值在0到255的范围内。

那些是Latin-1码点,对于其他值,决定是否将其视为错误,或者用代码点127(我最喜欢的ASCII“删除”)或问号或其他替换。


C++标准库定义了一个std::codecvt专业化可用于此操作,

template<>
codecvt<char32_t, char, mbstate_t>

C++11 §22.4.1.4/3:“codecvt <char32_t, char, mbstate_t>的特化可以在UTF-32编码和UTF-8编码之间进行转换”


这很有效,因为Unicode最初就被定义为ISO-8859-1的超集。参见http://en.wikipedia.org/wiki/Unicode#Origin_and_development。附:作为转换的起点,我建议https://dev59.com/TXVC5IYBdhLWcg3w51ry#148766。 - Mark Ransom
但是,但是,在C++17中std::codecvt不是已经被弃用了吗? - Константин Ван

2
C++11实现的Alf的建议
#include <string>
#include <codecvt>
#include <algorithm>
#include <iterator>
auto i = u8"H€llo Wørld";
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8;
auto wide = utf8.from_bytes(i);
std::string out;
out.reserve(wide.length());
std::transform(wide.cbegin(), wide.cend(), std::back_inserter(out),
           [](const wchar_t c) { return (c <= 255) ? c : '?'; });
// out now contains "H?llo W\xf8rld"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接