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

问题描述 投票:0回答:11

我正在尝试打印俄语“ф”(U+0444西里尔小写字母EF)字符,其十进制代码为1092。使用C++,如何打印出这个字符?我本以为以下内容会起作用,但是......

int main (){
   wchar_t f = '1060';
   cout << f << endl;
}
c++ unicode iostream cout wchar-t
11个回答
79
投票

要表示角色,您可以使用通用角色名称(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

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

#include <iostream>

int main() {
    std::cout << "Hello, ф or \u0444!\n";
}

此程序要求“ф”可以用单个字符表示。在 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";
}

可移植代码更加困难。


18
投票

使用

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

  const char *s  = u8"\u0444";
  cout << s << endl;

12
投票

最终,这完全取决于平台。不幸的是,标准 C++ 对 Unicode 的支持非常差。对于 GCC,您必须将其设置为窄字符串,因为它们使用 UTF-8,而 Windows 需要宽字符串,并且您必须输出到

wcout

// GCC
std::cout << "ф";
// Windoze
wcout << L"ф";

10
投票

此代码适用于 Linux(C++11GeanyGCC 7.4

g++
。2018-12-06)):

#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 "";
}

更多:


8
投票

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

// Save as UTF-8 without a signature
#include <stdio.h>
#include<windows.h>

int main (){
    SetConsoleOutputCP(65001);
    printf("ф\n");
}

它不是 Unicode,但它可以工作 — Windows-1251 而不是 UTF-8:

// Save as Windows 1251
#include <iostream>
#include<windows.h>

using namespace std;

int main (){
    SetConsoleOutputCP(1251);
    cout << "ф" << endl;
}

3
投票

'1060'
是四个字符,在标准下无法编译。如果您的宽字符与 Unicode 1:1 匹配,您应该将字符视为数字(检查您的区域设置)。

int main (){
    wchar_t f = 1060;
    wcout << f << endl;
}

1
投票

特别感谢here的回答,或多或少有相同的问题。

对我来说,我所需要的只是

setlocale(LC_ALL, "en_US.UTF-8");

然后,我什至可以使用原始的

wchar_t
字符。


1
投票

我需要在 UI 中显示该字符串并将其保存到 XML 配置文件中。上面指定的格式适用于 C++ 中的字符串,我想补充一点,通过将“\u”替换为“&#x”并添加“;”,我们可以为特殊字符提供 xml 兼容的字符串。在最后。

例如:

C++:“\u0444”→ XML:

"&#x0444;"


0
投票

在 Linux 中,我可以这样做:

std::cout << "ф";

我只是从这里复制粘贴字符,至少对于我尝试过的随机样本来说它没有失败。


0
投票

Linux下的另一种解决方案:

string a = "Ф";
cout << "Ф = \xd0\xa4 = " << hex
     << int(static_cast<unsigned char>(a[0]))
     << int(static_cast<unsigned char>(a[1])) << " (" << a.length() << "B)" << endl;

string b = "√";
cout << "√ = \xe2\x88\x9a = " << hex
     << int(static_cast<unsigned char>(b[0]))
     << int(static_cast<unsigned char>(b[1]))
     << int(static_cast<unsigned char>(b[2])) << " (" << b.length() << "B)" << endl;

0
投票

在 C++23 中,您可以使用支持 Unicode 的

std::print

#include <print>

int main () {
  std::print("{}\n", "ф");
}

std::print
广泛使用之前,您可以使用开源 {fmt} 库,它基于 (godbolt):

#include <fmt/core.h>

int main () {
  fmt::print("{}\n", "ф");
}

只需确保您的文字编码是 UTF-8,这通常是大多数平台上的默认编码,并且在 Windows/MSVC 上通过

/utf-8
启用它。

免责声明:我是 {fmt} 和 C++23 的作者

std::print

© www.soinside.com 2019 - 2024. All rights reserved.