Как печатать символ Unicode в С++?

Я пытаюсь напечатать русский символ "ф" (U + 0444 CYRILLIC SMALL LETTER EF), которому присваивается код десятичного знака 1092. Используя С++, как я могу распечатать этот символ? Я бы подумал, что что-то вроде этого будет работать, но...

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

Ответ 1

Для представления символа вы можете использовать универсальные имена символов (UCN). Символ "ф" имеет значение Unicode U + 0444, поэтому на С++ вы можете записать его "\ 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";
}

Эта программа не требует, чтобы 'ф' можно было представить в одном char. В 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";
}

Портативный код сложнее.

Ответ 2

В конечном счете, это полностью зависит от платформы. Поддержка Unicode, к сожалению, очень бедна в стандартном С++. Для GCC вам нужно будет сделать узкую строку, поскольку они используют UTF-8, а Windows требует широкую строку, и вы должны вывести на wcout.

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

Ответ 3

При компиляции с помощью -std=c++11 можно просто

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

Ответ 4

Если вы используете Windows (обратите внимание, мы используем printf(), а не cout):

//Save As UTF8 without signature
#include <stdio.h>
#include<windows.h>
int main (){
    SetConsoleOutputCP(65001); 
    printf("ф\n");
}

Не работает Unicode, а работает - 1251 вместо UTF8:

//Save As Windows 1251
#include <iostream>
#include<windows.h>
using namespace std;
int main (){
    SetConsoleOutputCP(1251); 
    cout << "ф" << endl;
}

Ответ 5

'1060' - четыре символа и не будет компилироваться под стандартом. Вы должны просто рассматривать символ как число, если ваши широкие символы соответствуют 1:1 с Unicode (проверьте настройки языка).

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

Ответ 6

В Linux я могу просто сделать:

std::cout << "ф";

Я просто скопировал символы из здесь, и это не сработало, по крайней мере, для случайной выборки, которую я пробовал.

Ответ 7

Другое решение в 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;

Ответ 8

Мне нужно было показать строку в пользовательском интерфейсе, а также сохранить ее в файле конфигурации xml. Указанный выше формат подходит для строки в c++, я хотел бы добавить, что мы можем иметь строку, совместимую с xml для специального символа, заменив "\ u" на "& # x" и добавив ";" в конце.

Например: c++: "\ u0444" → XML: "&#x0444;"

Ответ 9

Этот код работает в Linux (С++ 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 "";
}

Больше: