C ++ unicode字符打印

时间:2013-06-05 16:07:36

标签: c++ unicode cout

我需要使用iostream在Linux终端上打印一些unicode字符。虽然发生了奇怪的事情。我写的时候:

cout << "\u2780";

我得到:,这几乎就是我想要的。但是,如果我写:

cout << '\u2780';

我得到:14851712

问题是,我不知道在编译时要打印的确切字符。所以我想做点什么:

int x;
// some calculations...
cout << (char)('\u2780' + x);

打印:。使用wcoutwchar_t代替也不起作用。如何正确打印?

从我在互联网上发现的内容来看,我直接从Debian Wheezy存储库中使用g ++ 4.7.2编译器似乎很重要。

4 个答案:

答案 0 :(得分:6)

Unicode字符\u2780超出char数据类型的范围。您应该收到此编译器警告,告诉您:(至少我的g ++ 4.7.3给出了它)

test.cpp:6:13: warning: multi-character character constant [-Wmultichar]

如果你想使用像U + 2780这样的字符作为单个单元,你必须使用widechar数据类型wchar_t,或者如果你足够幸运能够使用C ++ 11,{ {1}}或char32_t。请注意,一个16位单元不足以表示全部Unicode字符。

如果这对您不起作用,可能是因为默认的“C”语言环境不支持非ASCII输出。要解决该问题,您可以在程序开头调用char16_t;这样你就可以输出用户语言环境支持的全部字符:(可能支持也可能不支持你使用的所有字符)

setlocale

答案 1 :(得分:4)

写作时

cout << "\u2780";

编译器将\ u2780转换为执行字符集中该字符的相应编码。这可能是UTF-8,因此字符串最终有四个字节(三个用于字符,一个用于空终止符)。

如果要在运行时生成字符,那么在运行时需要一些方法来执行与编译器在编译时进行的UTF-8相同的转换。


C ++ 11提供了一个方便的wstring_convert模板和codecvt方面,可以做到这一点,但libstdc ++,gcc附带的标准库实现,还没有实现它们(从gcc 4.8开始) 。以下显示了如何使用这些功能,但您需要使用不同的标准库实现或等待libstdc ++来实现它们。

#include <codecvt>

int main() {
  char32_t base = U'\u2780';

  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
  std::cout << convert.to_bytes(base + 5) << '\n';
}

您还可以使用任何其他生成UTF-8的方法。例如,iconv,ICU和手动使用pre-C ++ 11 codecvt_byname facet都可以。 (我没有展示这些示例,因为该代码比wstring_convert允许的简单代码更复杂。)


一个适用于少量字符的替代方法是使用文字创建一个字符串数组。

char const *special_character[] = { "\u2780", "\u2781", "\u2782",
  "\u2783", "\u2784", "\u2785", "\u2786", "\u2787", "\u2788", "\u2789" };

std::cout << special_character[i] << '\n';

答案 2 :(得分:0)

由于C ++11§2.14.3/ 1:

,程序打印整数
  

多字符文字,或包含在执行字符集中无法表示的单个c-char的普通字符文字,是条件支持的,类型为int,并且具有实现定义的值。

执行字符集是char可以表示的内容,即ASCII。

你得到的是14851712,或十六进制e29e80,这是U + 2780的UTF-8表示。将UTF-8(一种多字节编码)放入int是一种疯狂和愚蠢的行为,但这是你从“有条件支持的,实现定义的”功能中获得的。

要获取UTF-32值,请使用U'\u2780'。第一个U指定char32_t类型和UTF-32编码(即最多31位但没有代理对)。第二个\u指定包含代码点的通用字符名称。要获得与wcout兼容的值,请使用L'\u2780',但这不一定使用Unicode运行时值,也不会超过两个字节的存储空间。

至于可靠地操作和打印Unicode代码点,正如其他答案所指出的那样,C ++标准尚未完全实现。 Joni的答案是最好的方法,但它仍然假设编译器和用户的环境使用相同的语言环境,这通常是不正确的。

您还可以使用u8"\u2780"在源中指定UTF-8字符串,并使用std::locale::global( std::locale( "en_US.UTF-8" ) );之类的内容强制运行时环境为UTF-8。但那仍然有粗糙的边缘。 Joni建议使用来自std::setlocale的C接口<clocale>而不是来自std::locale::global的C ++接口<locale>,这是在OS X上的GCC中打破C ++接口的一种解决方法也许是其他平台。这些问题对平台非常敏感,因此您的Linux发行版可能会在自己的GCC包中添加补丁。

答案 3 :(得分:0)

在Linux中,我已经成功地以最天真的方式直接打印出任何unicode:

std::cout << "ΐ , Α, Β, Γ, Δ, ,Θ , Λ, Ξ, ... ±, ... etc"