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

Posted

技术标签:

【中文标题】将字符串从 UTF-8 转换为 ISO-8859-1【英文标题】:Convert string from UTF-8 to ISO-8859-1 【发布时间】:2014-05-15 22:27:16 【问题描述】:

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

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

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

【问题讨论】:

这听起来像是一个潜在的大项目——而且正是像 iconv 这样的库所擅长的。以正确的方式做事有什么问题? 如果这是唯一可用的方法,我可以使用 iconv。它绝对不是可以想象的最优雅的 C++ 解决方案。像s.toEncoding("ISO-8859-1") 这样的东西会更优雅。我的意思是,即使我在 iconv 中执行此操作,我也不清楚如何使用带有 string 输入的库。 不确定,但可能会有所帮助:openldap.org/lists/openldap-devel/200304/msg00123.html 【参考方案1】:

我将修改我的代码 from another answer 以实施 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 string 进来。如果你做到了 string-to-string 那就完美了。 @ChrisRedford,只需使用mystr.c_str() 调用它。我喜欢 const char * 输入,因为它更灵活。 由于输入来自std::string,只需将const char * in 替换为const std::string&amp; in,然后创建一个分配in.c_str() 的本地变量char* 以供循环使用,并且使用in.size() 作为循环计数器而不是*in != 0。或者使用 in.begin()in.end() 迭代器。 如果您正在寻找将带有 utf-8 字符的 std::string 转换为 iso 8859 或 Windows 1252 编码的方法,这里有一个函数可以使用硬编码转换,无需调用到codecvt_utf8()、iconv()或类似函数。它使用类似的 Mark Ransom 循环。 github.com/agnasg/utils @GustavoRodríguez 这很容易做到,因为 Unicode 对其前 256 个代码点采用了 Latin-1 字符集 - 无需翻译。【参考方案2】:

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

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

这些是 Latin-1 代码点,对于其他值,决定是否要将其视为错误,或者可能替换为代码点 127(我的最爱,ASCII“del”)或问号之类的。


C++ 标准库定义了一个可以使用的std::codecvt 特化,

template<>
codecvt<char32_t, char, mbstate_t>

C++11 §22.4.1.4/3:“特化 codecvt &lt;char32_t, char, mbstate_t&gt; 在 UTF-32 和 UTF-8 编码方案”

【讨论】:

这很好用,因为 Unicode 一开始就被定义为 ISO-8859-1 的超集。见en.wikipedia.org/wiki/Unicode#Origin_and_development作为转换的起点,我建议***.com/a/148766/5987 但是,但是,std::codecvt 不是在 C++17 中被弃用了吗?【参考方案3】:

在 C++11 中实现的 Alfs 建议

#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"

【讨论】:

以上是关于将字符串从 UTF-8 转换为 ISO-8859-1的主要内容,如果未能解决你的问题,请参考以下文章

使用 NSString 将 UTF-8 编码转换为 ISO 8859-1 编码

iconv 中的输出缓冲区为空,同时从 ISO-8859-1 转换为 UTF-8

Scala - 从 ISO-8859-1 转换为 UTF-8 会给外来字符带来陌生感

Python 中 ISO-8859-2 和 UTF-8 之间的转换

将 ISO-8859-1 转换为 UTF-8 [重复]

将 ISO-8859-1 / Latin-1 转换为字符串 (UTF-8) 的选项都有哪些?