如何在C++中打印Unicode字符?

Jam*_*sev 45 c++ unicode iostream cout wchar-t

我正在尝试打印俄语"ф"(U + 0444 CYRILLIC SMALL LETTER EF)字符,其代码为十进制1092.使用C++,我该如何打印出这个角色?我会想到下面的内容会起作用,但......

int main (){
   wchar_t f = '1060';
   cout << f << endl;
}
Run Code Online (Sandbox Code Playgroud)

bam*_*s53 51

要表示字符,您可以使用通用字符名称(UCN).字符'ф'的Unicode值为U + 0444,因此在C++中您可以将其写为'\ u0444'或'\ U00000444'.此外,如果源代码编码支持此字符,那么您可以直接在源代码中编写它.

// both of these assume that the character can be represented with
// a single char in the execution encoding
char b = '\u0444';
char a = '?'; // this line additionally assumes that the source character encoding supports this character
Run Code Online (Sandbox Code Playgroud)

打印此类字符取决于您要打印的内容.如果您要打印到Unix终端仿真器,终端仿真器正在使用支持该字符的编码,并且该编码与编译器的执行编码匹配,那么您可以执行以下操作:

#include <iostream>

int main() {
    std::cout << "Hello, ? or \u0444!\n";
}
Run Code Online (Sandbox Code Playgroud)

该程序要求'ф'可以用单个字符表示.在OS X和大多数现代Linux安装上,这都可以正常工作,因为源代码,执行代码和控制台编码都是UTF-8(支持所有Unicode字符).

Windows的情况比较困难,不同的权衡方式有不同的可能性.

可能是最好的,如果你不需要可移植代码(你将使用wchar_t,这应该在每个其他平台上都应该避免),就是将输出文件句柄的模式设置为仅采用UTF-16数据.

#include <iostream>
#include <io.h>
#include <fcntl.h>

int main() {
    _setmode(_fileno(stdout), _O_U16TEXT);
    std::wcout << L"Hello, \u0444!\n";
}
Run Code Online (Sandbox Code Playgroud)

便携代码更难.

  • ?我很确定'\ u0444'不适合char,除非编译器将char提升为int,但如果你想要这种行为,你应该使用int. (2认同)

Pup*_*ppy 10

最终,这完全取决于平台.遗憾的是,在标准C++中,Unicode支持非常差.对于GCC,你必须使它成为一个窄字符串,因为它们使用UTF-8,而Windows需要一个宽字符串,你必须输出到wcout.

// GCC
std::cout << "?";
// Windoze
wcout << L"?";
Run Code Online (Sandbox Code Playgroud)

  • @BillyONeal你不在C++中使用代理代码点(实际上代理代码点是完全禁止的).您使用格式`\ UXXXXXXXX`. (9认同)
  • GCC不一定使用UTF-8,并且可用于Windows.`std :: wcout`也是Windows之外的一个选项. (2认同)
  • @Jam`'\ u0400'`是一个**字符的缩写**.您似乎假设执行字符集中存在`\ u0400`.根据N3242 [lex.ccon]/5:"通用字符名称被转换为编码,在相应的执行字符集中,被命名为.如果没有这样的编码,通用字符名称是转换为实现定义的编码." (2认同)

Jam*_*sev 10

编译时-std=c++11,可以简单地进行编译

  const char *s  = u8"\u0444";
  cout << s << endl;
Run Code Online (Sandbox Code Playgroud)

  • 让我推荐[Boost.Nowide](http://cppcms.com/files/nowide/html/)以便携方式将UTF-8字符串打印到终端,因此上述代码几乎不会改变. (3认同)
  • @ybungalobill,您的评论本身就值得一个答案。你介意创造一个吗? (2认同)

vla*_*vic 6

如果您使用Windows(注意,我们使用的是printf(),而不是cout):

//Save As UTF8 without signature
#include <stdio.h>
#include<windows.h>
int main (){
    SetConsoleOutputCP(65001); 
    printf("?\n");
}
Run Code Online (Sandbox Code Playgroud)

不是Unicode而是工作 - 1251而不是UTF8:

//Save As Windows 1251
#include <iostream>
#include<windows.h>
using namespace std;
int main (){
    SetConsoleOutputCP(1251); 
    cout << "?" << endl;
}
Run Code Online (Sandbox Code Playgroud)


小智 6

此代码适用于 Linux(C++11、geany、g++ 7.4.0):

#include <iostream>

using namespace std;


int utf8_to_unicode(string utf8_code);
string unicode_to_utf8(int unicode);


int main()
{
    cout << unicode_to_utf8(36) << '\t';
    cout << unicode_to_utf8(162) << '\t';
    cout << unicode_to_utf8(8364) << '\t';
    cout << unicode_to_utf8(128578) << endl;

    cout << unicode_to_utf8(0x24) << '\t';
    cout << unicode_to_utf8(0xa2) << '\t';
    cout << unicode_to_utf8(0x20ac) << '\t';
    cout << unicode_to_utf8(0x1f642) << endl;

    cout << utf8_to_unicode("$") << '\t';
    cout << utf8_to_unicode("¢") << '\t';
    cout << utf8_to_unicode("€") << '\t';
    cout << utf8_to_unicode("") << endl;

    cout << utf8_to_unicode("\x24") << '\t';
    cout << utf8_to_unicode("\xc2\xa2") << '\t';
    cout << utf8_to_unicode("\xe2\x82\xac") << '\t';
    cout << utf8_to_unicode("\xf0\x9f\x99\x82") << endl;

    return 0;
}


int utf8_to_unicode(string utf8_code)
{
    unsigned utf8_size = utf8_code.length();
    int unicode = 0;

    for (unsigned p=0; p<utf8_size; ++p)
    {
        int bit_count = (p? 6: 8 - utf8_size - (utf8_size == 1? 0: 1)),
            shift = (p < utf8_size - 1? (6*(utf8_size - p - 1)): 0);

        for (int k=0; k<bit_count; ++k)
            unicode += ((utf8_code[p] & (1 << k)) << shift);
    }

    return unicode;
}


string unicode_to_utf8(int unicode)
{
    string s;

    if (unicode>=0 and unicode <= 0x7f)  // 7F(16) = 127(10)
    {
        s = static_cast<char>(unicode);

        return s;
    }
    else if (unicode <= 0x7ff)  // 7FF(16) = 2047(10)
    {
        unsigned char c1 = 192, c2 = 128;

        for (int k=0; k<11; ++k)
        {
            if (k < 6)  c2 |= (unicode % 64) & (1 << k);
            else c1 |= (unicode >> 6) & (1 << (k - 6));
        }

        s = c1;    s += c2;

        return s;
    }
    else if (unicode <= 0xffff)  // FFFF(16) = 65535(10)
    {
        unsigned char c1 = 224, c2 = 128, c3 = 128;

        for (int k=0; k<16; ++k)
        {
            if (k < 6)  c3 |= (unicode % 64) & (1 << k);
            else if (k < 12) c2 |= (unicode >> 6) & (1 << (k - 6));
            else c1 |= (unicode >> 12) & (1 << (k - 12));
        }

        s = c1;    s += c2;    s += c3;

        return s;
    }
    else if (unicode <= 0x1fffff)  // 1FFFFF(16) = 2097151(10)
    {
        unsigned char c1 = 240, c2 = 128, c3 = 128, c4 = 128;

        for (int k=0; k<21; ++k)
        {
            if (k < 6)  c4 |= (unicode % 64) & (1 << k);
            else if (k < 12) c3 |= (unicode >> 6) & (1 << (k - 6));
            else if (k < 18) c2 |= (unicode >> 12) & (1 << (k - 12));
            else c1 |= (unicode >> 18) & (1 << (k - 18));
        }

        s = c1;    s += c2;    s += c3;    s += c4;

        return s;
    }
    else if (unicode <= 0x3ffffff)  // 3FFFFFF(16) = 67108863(10)
    {
        ;  // actually, there are no 5-bytes unicodes
    }
    else if (unicode <= 0x7fffffff)  // 7FFFFFFF(16) = 2147483647(10)
    {
        ;  // actually, there are no 6-bytes unicodes
    }
    else  ;  // incorrect unicode (< 0 or > 2147483647)

    return "";
}
Run Code Online (Sandbox Code Playgroud)

更多的: