【问题标题】:Does C++ support converting between character encodings other than UTF-8, UTF-16, and UTF-32?C++ 是否支持在 UTF-8、UTF-16 和 UTF-32 以外的字符编码之间进行转换?
【发布时间】:2014-07-03 21:25:16
【问题描述】:

我了解 C++11 中的std::codecvt<char16_t, char> 执行 UTF-16 和 UTF-8 之间的转换,std::codecvt<char32_t, char> 执行 UTF-32 和 UTF-8 之间的转换。是否可以在 UTF-8 和 ISO 8859-1 之间进行转换?

考虑:

const char* s = "\u00C0";

如果我打印此字符串并且我的终端编码设置为 UTF-8,我将看到字符 À。但是,如果我将终端的编码设置为 ISO 8859-1,则打印该字符串将不会打印出所需的字符。如果我的终端编码设置为 ISO 8859-1,我如何将 s 转换为字符串,在打印时将显示字符 À

我知道这可以通过 iconv 之类的库来完成,但我很好奇是否可以仅使用 C++ 标准库来完成。我问这个问题不是因为我不想使用 iconv,而是因为我不太了解语言环境在 C++ 中是如何工作的。

【问题讨论】:

  • C++ 标准中没有任何明确的非 Unicode 编码。您拥有可以相互转换的“系统编码”,并且可能指示您的系统使用 ISO 8859-1(可能通过环境变量);或使用显式转换库,例如 iconv
  • @KerrekSB,您将如何与“系统编码”相互转换?
  • 查看底部附近的表格of this documentation。例如。 mbrtoc32 从系统的窄编码转换为 UTF-32。 (你可能想知道where the <cuchar> header is...)

标签: c++ c++11 character-encoding locale


【解决方案1】:

除了标准的强制编码外,C++ 还支持通过语言环境定义的实现定义的编码列表:

#include <locale>
#include <codecvt>
#include <iostream>

template <typename Facet>
struct usable_facet : Facet {
  using Facet::Facet;
};

using codecvt = usable_facet<std::codecvt_byname<wchar_t, char, std::mbstate_t>>;

int main() {
  std::wstring_convert<codecvt> convert(new codecvt(".1252")); // platform specific locale strings

  std::wstring w = convert.from_bytes("\u00C0");
}

不幸的是,wchar_t 的一件事是标准 mandates 仅对所有语言环境使用固定宽度的编码,但不要求它在不同的语言环境中使用 same 编码语言环境,因此您不能使用一种语言环境可移植地转换为wchar_t,然后再使用不同的语言环境将其转换回char

使用 std::mbrtoc32 等函数和相关函数可能会为此类转换提供一些可移植的支持,但尚未广泛实施。

我知道这可以通过 iconv 之类的库来完成,但我很好奇是否可以仅使用 C++ 标准库来完成。我问这个问题不是因为我不想使用 iconv,而是因为我不太了解语言环境在 C++ 中是如何工作的。

语言环境库的设计并不适合现代使用。 C 和 C++ 本身对编码与字符集感到困惑,并且语言环境将词汇和拼写问题与编码等计算方面混为一谈。

语言环境如何工作是一个比适用于 stackoverflow 答案更广泛的主题,但该主题上有 books。您可能还需要阅读特定于平台的材料,因为该标准并没有真正为大部分功能提供任何上下文。例如,语言环境库支持消息目录,但不会告诉您它们是什么或您实际上会如何make one,因为 C++ 没有标准化该功能。

【讨论】:

  • 你能举一个实际编译的例子吗?我收到有关具有受保护析构函数的 codecvt 对象的错误。
  • @Brian 我已经更新了代码以修复几个错别字。 usable_facet 模板解决了受保护的析构函数问题(尽管在 Microsoft 的实现中,没有这个技巧就可以访问析构函数)。请注意,new codecvt 表达式不引用 std::codecvt
【解决方案2】:

如果您想仅使用 C++ 标准库的工具将 UTF-8 转换为 ISO 8859-1:

  1. 转换 UTF-8 → UTF-32(转换为 UTF-16 也可以)。
  2. 每个编码值

由于这有一个答案,而几乎任何其他所需的特定编码都没有答案,我怀疑这个问题是为了回答而构建的。

标准库转换仅支持另一种编码,即执行字符集的未指定多字节编码,例如通过mbstowcs(从形式上讲,宽字符编码不需要是 Unicode,所以形式上还有另一种未指定的编码,但实际上它是 Unicode,即 UTF-16 或 UTF-32)。


我想知道是否应该添加一个代码示例,但由于对这个答案没有兴趣(对于问题的“我很好奇它是否可以仅使用 C++ 标准库来完成”),我认为这将是浪费精力。

【讨论】:

    猜你喜欢
    • 2020-01-28
    • 2010-09-12
    • 2014-11-14
    • 1970-01-01
    • 2012-07-23
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多