如何在C++中使用Unicode?

Dox*_*Dox 28 c++ string unicode

假设一个非常简单的程序:

  • 问一个名字.
  • 将名称存储在变量中.
  • 在屏幕上显示可变内容.

它是如此简单,是人们学习的第一件事.

但我的问题是,如果我使用日文字符输入名称,我不知道如何做同样的事情.

所以,如果您知道如何在C++中执行此操作,请向我展示一个示例(我可以编译和测试)

谢谢.


user362981:谢谢你的帮助.我编译了您编写的代码没有问题,它们出现了控制台窗口,我无法在其上输入任何日文字符(使用IME).此外,如果我将代码中的单词("hello")更改为包含日语字符的单词,它也不会显示这些单词.

Svisstack:也谢谢你的帮助.但是当我编译你的代码时,我收到以下错误:

warning: deprecated conversion from string constant to 'wchar_t*'
error: too few arguments to function 'int swprintf(wchar_t*, const wchar_t*, ...)'
error: at this point in file
warning: deprecated conversion from string constant to 'wchar_t*'
Run Code Online (Sandbox Code Playgroud)

Tha*_*tos 38

你会得到很多关于宽字的答案.宽字符,特别wchar_t 是不等于Unicode.您可以使用它们(有一些陷阱)来存储Unicode,就像您一样unsigned char.wchar_t是非常依赖系统的.引用Unicode标准版本5.2,第5章:

对于wchar_t宽字符类型,ANSI/ISO C提供包含固定宽度,宽字符.ANSI/ISO C将宽字符集的语义留给特定实现,但要求便携式C执行集中的字符通过零扩展对应于它们的宽字符等价物.

然后

宽度wchar_t是特定于编译器的,可以小到8位.因此,需要可通过任何C或C++编译器移植的程序不wchar_t 应用于存储Unicode文本.该wchar_t类型用于存储编译器定义的宽字符,在某些编译器中可能是Unicode字符.

所以,它是实现定义的.这里有两个实现:在Linux上,wchar_t宽度为4个字节,表示UTF-32编码的文本(无论当前的语言环境如何).(BE或LE取决于您的系统,无论哪个是原生的.)然而,Windows有2字节宽wchar_t,并用它们表示UTF-16代码单元.完全不同.

更好的途径:了解区域设置,因为您需要了解它.例如,因为我的环境设置使用UTF-8(Unicode),所以以下程序将使用Unicode:

#include <iostream>

int main()
{
    setlocale(LC_ALL, "");
    std::cout << "What's your name? ";
    std::string name;
    std::getline(std::cin, name);
    std::cout << "Hello there, " << name << "." << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

...

$ ./uni_test
What's your name? ?? ??
Hello there, ?? ??.
$ echo $LANG
en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)

但是没有关于它的Unicode.它只是读取以UTF-8形式出现的字符,因为我的环境设置如此.我可以很容易地说"哎呀,我是捷克人,让我们使用ISO-8859-2":突然之间,程序正在输入ISO-8859-2,但是因为它只是反刍它,所以没关系,该程序仍将正常执行.

现在,如果那个例子以我的名义读过,然后试图把它写成一个XML文件,然后愚蠢地写<?xml version="1.0" encoding="UTF-8" ?>在顶部,那么当我的终端是UTF-8时会是正确的,但是当我的终端在ISO-8859-2.在后一种情况下,它需要在将其序列化为XML文件之前进行转换.(或者,只需编写ISO-8859-2作为XML文件的编码.)

在许多POSIX系统上,当前的语言环境通常是UTF-8,因为它为用户提供了几个优点,但这不能保证.输出UTF-8 stdout通常是正确的,但并非总是如此.假设我使用的是ISO-8859-2:如果你盲目地将ISO-8859-1"è"(0xE8)输出到我的终端,我会看到一个"č"(0xE8).同样,如果您输出UTF-8"è"(0xC3 0xA8),我会看到(ISO-8859-2)"è"(0xC3 0xA8).这种不正确的字符被称为Mojibake.

通常,你只是在改变数据,这并不重要.当您需要序列化数据时,这通常会发挥作用.(许多互联网协议使用UTF-8或UTF-16,例如:如果您从ISO-8859-2终端获得数据,或者在Windows-1252中编码的文本文件,那么您必须转换它,或者您将送Mojibake.)

遗憾的是,这是关于C和C++中Unicode支持的状态.您必须记住:这些语言实际上与系统无关,并且不会绑定到任何特定的方式.这包括字符集.然而,有很多库用于处理Unicode和其他字符集.

最后,它并不是那么复杂:了解您的数据编码是什么,并知道您的输出应该是什么编码.如果它们不相同,则需要进行转换.这适用于您使用std::coutstd::wcout.在我的例子中,stdinstd::cinstdout/ std::cout有时在UTF-8,有时ISO-8859-2.


Eva*_*nED 2

尝试用 wcout 替换 cout,用 wcin 替换 cin,用 wstring 替换 string。根据您的平台,这可能有效:

#include <iostream>
#include <string>

int main() {
  std::wstring name;
  std::wcout << L"Enter your name: "; 
  std::wcin >> name;
  std::wcout << L"Hello, " << name << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

还有其他方法,但这是“最小改变”的答案。