C++是否支持除UTF-8、UTF-16和UTF-32以外的字符编码转换?

4
我知道在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 - Kerrek SB
@KerrekSB,你如何转换到和从“系统编码”中进行转换? - Brian Bi
请查看此文档底部的表格。例如,mbrtoc32将系统的窄编码转换为UTF-32。(你可能会想知道<cuchar>头文件在哪里...) - Kerrek SB
2个回答

3
除了标准强制编码,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 的一件事情是标准 规定 它只能使用固定宽度编码来处理所有语言环境,但不要求在不同语言环境中使用相同的编码,因此不能使用一个语言环境将其转换为 wchar_t,然后再使用另一个语言环境将其转换回 char

可能存在一些可移植支持这种转换的函数,例如 std::mbrtoc32 和相关函数,但这些函数尚未被广泛实现。

我知道可以使用诸如 iconv 等库来完成此操作,但我想知道是否可以仅使用 C++ 标准库来完成。我提出这个问题并不是因为我不想使用 iconv,而是因为我不太理解 C++ 中的语言环境。

本地化库的设计并不适用于现代用法。C 和 C++ 本身对编码和字符集很困惑,而区域设置(locales)则将词汇和拼写问题与编码等计算方面混为一谈。
如何使用区域设置是一个比适合在 stackoverflow 上回答的话题更广泛的话题,但有相关书籍可供参考。您还可能需要阅读特定平台的材料,因为标准并没有为许多功能提供任何上下文。例如,区域设置库支持消息目录,但不告诉您它们是什么或者您应该如何创建一个,因为这种功能没有被 C++ 标准化。

能否给出一个实际可以编译的例子?我遇到一个关于codecvt对象具有受保护析构函数的错误。 - Brian Bi
@Brian 我已经更新了代码,修复了一些拼写错误。usable_facet模板解决了受保护的析构函数问题(尽管在Microsoft的实现中,析构函数可以在不使用此技巧的情况下访问)。请注意,new codecvt表达式不是指std::codecvt - bames53

0

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

  1. 将UTF-8 → UTF-32转换(转换为UTF-16也可以)。
  2. 每个编码值<256都是ISO 8859-1,其他则不是。

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

标准库转换仅支持另一种编码,即执行字符集的未指定多字节编码,例如通过mbstowcs(作为正式-追求严谨性,宽字符编码不需要是Unicode,因此在形式上还有另一种未指定的编码,但实际上它是Unicode,即UTF-16或UTF-32)。


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

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