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



我理解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++还支持通过区域设置实现定义的编码列表:

#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++中的区域设置是如何工作的。

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

区域如何工作是一个比适合stackoverflow答案更广泛的主题,但是有关于这个主题的书。您可能还需要阅读特定于平台的材料,因为该标准并没有真正为许多功能提供任何上下文。例如,locale库支持消息目录,但不告诉您它们是什么,也不告诉您如何实际创建一个,因为该功能未被c++标准化。

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

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

既然这有一个答案,而几乎任何其他期望的特定编码都没有答案,我怀疑这个问题是为了可回答而构造的。

标准库转换只支持另一种编码,即执行字符集的未指定的多字节编码,例如mbstowcs(作为一种形式-迂文的问题,宽字符编码不必是Unicode,因此正式存在另一种未指定的编码,但实际上是Unicode,即UTF-16或UTF-32)。


我想知道我是否应该添加一个代码示例,但是因为我对这个答案没有兴趣(对于这个问题,我很好奇是否可以只使用c++标准库来完成)我认为那是白费力气。

最新更新