C++中的十进制到Unicode字符

Fra*_*cis 2 c++ unicode ascii decimal

在输出时,如何将十进制数字225(例如225)转换为相应的Unicode字符?我可以将ASCII字符从十进制转换为如下字符:

int a = 97;
char b = a;
cout << b << endl;
Run Code Online (Sandbox Code Playgroud)

它输出字母"a",但当我使用数字225或任何非ascii字符时它只输出一个问号.

Bon*_*uin 7

如果出于某种原因您想完全自行处理此问题:

\n\n
void GetUnicodeChar(unsigned int code, char chars[5]) {\n    if (code <= 0x7F) {\n        chars[0] = (code & 0x7F); chars[1] = '\\0';\n    } else if (code <= 0x7FF) {\n        // one continuation byte\n        chars[1] = 0x80 | (code & 0x3F); code = (code >> 6);\n        chars[0] = 0xC0 | (code & 0x1F); chars[2] = '\\0';\n    } else if (code <= 0xFFFF) {\n        // two continuation bytes\n        chars[2] = 0x80 | (code & 0x3F); code = (code >> 6);\n        chars[1] = 0x80 | (code & 0x3F); code = (code >> 6);\n        chars[0] = 0xE0 | (code & 0xF); chars[3] = '\\0';\n    } else if (code <= 0x10FFFF) {\n        // three continuation bytes\n        chars[3] = 0x80 | (code & 0x3F); code = (code >> 6);\n        chars[2] = 0x80 | (code & 0x3F); code = (code >> 6);\n        chars[1] = 0x80 | (code & 0x3F); code = (code >> 6);\n        chars[0] = 0xF0 | (code & 0x7); chars[4] = '\\0';\n    } else {\n        // unicode replacement character\n        chars[2] = 0xEF; chars[1] = 0xBF; chars[0] = 0xBD;\n        chars[3] = '\\0';\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后使用它:

\n\n
char chars[5];\nGetUnicodeChar(225, chars);\ncout << chars << endl; // \xc3\xa1\n\nGetUnicodeChar(0x03A6, chars);\ncout << chars << endl; // \xce\xa6\n\nGetUnicodeChar(0x110000, chars);\ncout << chars << endl; // \xef\xbf\xbd\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,这只是标准的 UTF-8 编码算法,因此如果您的平台不采用 UTF-8,它可能无法正确呈现。(谢谢,@EmilioGaravaglia)

\n

  • 这是 UCS 到 UTF8 的转换。它的工作原理是假设用作控制台的终端是 UTF8,但用户情况可能并非如此。与大多数 Linux 发行版兼容,但在大多数“标准”语言环境下的 Windows 控制台上失败。 (2认同)

ric*_*ici 6

首先,不是你的C++程序将写入标准输出的字节串转换为可见字符; 它是你的终端(或者,更常见的是,这些天,你的终端模拟器).不幸的是,没有办法询问终端如何编码字符,因此需要将其配置到您的环境中; 通常,这是通过设置适当的locale环境变量来完成的.

像大多数与终端有关的事情一样,如果没有开发具有多年遗留软件和硬件的历史,那么区域设置配置系统可能会做得非常不同,其中大多数设计最初是在没有太多考虑细节的情况下设计的.喜欢重音字母,音节或表意文字.这就是生活.

Unicode非常酷,但是面对编写系统的计算机表示的特定历史,它也必须部署,这意味着面对软件工程中各种牢固但极其矛盾的观点,要做出很多妥协.社区,dicho sea de paso这是一个社区,在这个社区中,头部撞击更为普遍.Unicode最终成为或多或少成为标准的事实证明了其坚实的技术基础以及其发起人和设计师 - 尤其是马克戴维斯 - 的坚持不懈和政治技巧,尽管它基本上是二十多年来达到这一点.

这种谈判和妥协历史的一个方面是将Unicode字符串编码为位的方法不止一种.至少有三种方式,其中两种方式有两种不同的版本,具体取决于字节顺序; 而且,这些编码系统中的每一个都有其专用的风扇(因此,其教条的批评者).特别是,Windows早期决定使用大多数16位编码UTF-16,而大多数类似unix(类似)的系统使用可变长度的8到32位编码UTF-8.(从技术上讲,UTF-16也是16位或32位编码,但这超出了这种咆哮的范围.)

在Unicode之前,每个国家/地区/语言都使用他们自己的特殊8位编码(或者至少是那些语言用少于194个字符编写的国家/地区).因此,将编码配置为本地表示的一般配置的一部分是有意义的,例如月份名称,货币符号,以及将数字的整数部分与其小数分开的字符.既然Unicode上存在广泛的(但仍然很普遍)收敛,那么locales包含Unicode编码的特殊风格似乎很奇怪,因为所有的风格都可以表示相同的Unicode字符串,并且编码通常特定于特定的使用的软件比国家的特质.但它是,这就是为什么在我的Ubuntu盒子上,环境变量LANG被设置为es_ES.UTF-8而不仅仅是es_ES.(或者es_PE,应该是这样,除了我继续遇到该语言环境的小问题.)如果你使用的是linux系统,你可能会发现类似的东西.

从理论上讲,这意味着我的终端仿真器(konsole虽然它发生了,但有各种各样)希望看到UTF-8序列.事实上,konsole它足够聪明地检查语言环境设置并设置其默认编码以匹配,但我可以自由更改编码(或语言环境设置),并可能导致混淆.

因此,假设您的语言环境设置和终端使用的编码实际上是同步的,它们应该在配置良好的工作站上,然后返回到C++程序.现在,C++程序需要确定它应该使用哪种编码,然后从它使用的任何内部表示转换为外部编码.

幸运的是,如果您通过以下方式合作,C++标准库应该正确处理:

  1. 告诉标准库使用已配置的区域设置,而不是默认区域C(即仅根据英语的非重音字符)区域设置; 和

  2. 使用基于wchar_t(或其他一些宽字符格式)的字符串和iostream .

如果您这样做,理论上您不需要知道wchar_t标准库的含义,也不需要了解特定位模式对终端仿真器的意义.所以让我们试试:

#include <iostream>
#include <locale>

int main(int argc, char** argv) {
  // std::locale()   is the "global" locale
  // std::locale("") is the locale configured through the locale system
  // At startup, the global locale is set to std::locale("C"), so we need
  // to change that if we want locale-aware functions to use the configured
  // locale.
  // This sets the global" locale to the default locale. 
  std::locale::global(std::locale(""));

  // The various standard io streams were initialized before main started,
  // so they are all configured with the default global locale, std::locale("C").
  // If we want them to behave in a locale-aware manner, including using the
  // hopefully correct encoding for output, we need to "imbue" each iostream
  // with the default locale.
  // We don't have to do all of these in this simple example,
  // but it's probably a good idea.
  std::cin.imbue(std::locale());
  std::cout.imbue(std::locale());
  std::cerr.imbue(std::locale());
  std::wcin.imbue(std::locale());
  std::wcout.imbue(std::locale());
  std::wcerr.imbue(std::locale());

  // You can't write a wchar_t to cout, because cout only accepts char. wcout, on the
  // other hand, accepts both wchar_t and char; it will "widen" char. So it's
  // convenient to use wcout:
  std::wcout << "a acute: " << wchar_t(225) << std::endl;
  std::wcout << "pi:      " << wchar_t(960) << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这适用于我的系统.因人而异.祝好运.


小旁注:我遇到很多人认为wcout自动写"宽字符",因此使用它会产生UTF-16或UTF-32或其他东西.它没有.它产生的编码完全相同cout.差异不在于它的输出,而在于它作为输入接受的内容.事实上,它实际上并没有什么不同,cout因为它们都连接到同一个OS流,它只能有一个编码(一次).

你可能会问为什么有两个不同的iostreams 是必要的.为什么不能cout接受wchar_tstd::wstring价值观?我实际上并没有这个答案,但我怀疑它是不支付你不需要的功能的哲学的一部分.或类似的东西.如果你搞清楚了,请告诉我.