Форум программистов, компьютерный форум, киберфорум
bedvit
Войти
Регистрация
Восстановить пароль
Рейтинг: 2.86. Голосов: 7.

Настройка консоли:Unicode, размер, шрифт (корректный ввод/вывод строк с кириллицей, пробелами, знаками юникода) С++

Запись от bedvit размещена 07.12.2017 в 13:15
Обновил(-а) bedvit 26.10.2022 в 11:11

Простой способ больше не вспоминать о кодировках CP866, ANSI(рус.:CP1251) и костылях, типа "setlocale(LC_ALL, "Russian")" или "SetConsoleCP(1251); SetConsoleOutputCP(1251);"
Применимо (протестировано) для Microsoft Visual Studio.
В данном блоге я не буду рассматривать разные способы ввода\вывода в консоль строк с нужной кодировкой и их дальнейшего корректного использования в коде (в сети их предостаточно)
Я рассмотрю и подробно распишу - один, который, по моему мнению, довольно прост, универсален и снимает все проблемы с вводом/выводом строк на разных языках, в т.ч. с пробелами.

Этот способ - переход на Unicode.
Если точнее, то на Unicode(UTF-16) - стандартный 2-х байтный (16-битный). Родной для Win (UTF-16LE) и других программ.

Итак, если вам это подходит, прошу к дальнейшему чтению и обсуждению...

Шаг.1 Создаем проект "Unicode" в Студии ("Файл"-"Создать проект"-"С++-консольное приложение")
Меняем
C++
1
int main()
на широкую версию
C++
1
int wmain(int argc, wchar_t* argv[], wchar_t *envp[])
Шаг.2 Переводим ввод\вывод в консоль на Unicode
C++
1
2
3
    _setmode(_fileno(stdout), _O_U16TEXT);
    _setmode(_fileno(stdin), _O_U16TEXT);
    _setmode(_fileno(stderr), _O_U16TEXT);
Шаг.3 Переводим на Unicode, собственно сам проект: "Файл" - "Сохранить "Unicode.cpp" как" ... далее... на кнопке "сохранить"-список "сохранить с кодировкой" (на вопрос "заменить?" жмем - "да") - выбираем "Юникод, кодовая страница 1200" - "ОК"
или в общепринятый UTF-8 (в Студии по умолчанию кодировка для проектов "UTF-8 с сигнатурой", оставляем её)

Шаг.4 Добавляем возможность поменять размер окна (если вам не нужно можно эту часть пропустить) и сам шрифт (для возможности отображать Unicode-символы) - я выбрал стандартный, присутствующий у всех - Lucida Console.
Если у вас установлен нужный шрифт с поддержкой нужных вам символов, эту часть то же можно пропустить.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
////////////////////меняем размер консоли - опционально - можно пропустить
        system("mode con cols=100 lines=50"); //размер окна, вывод нужного количества строк в консоль
        HANDLE  hout = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD  size{ 100,100 };//символов строки, строк
        SetConsoleScreenBufferSize(hout, size);//размер буфера
        ///////////////////////////////////Меняем шрифт для отображения символов Unicode, можно пропустить - если у вас установлен такой
        CONSOLE_FONT_INFOEX cfi;
        cfi.cbSize = sizeof(CONSOLE_FONT_INFOEX);
        cfi.nFont = 0;
        cfi.dwFontSize.X = 8;
        cfi.dwFontSize.Y = 14;
        cfi.FontFamily = FF_DONTCARE;
        cfi.FontWeight = FW_NORMAL;
        wcscpy_s(cfi.FaceName, L"Lucida Console");
        SetCurrentConsoleFontEx(hout, false, &cfi);
        ///////////////////////////////////Меняем шрифт
Шаг.5 Итоговый - добавляем сам код для тестирования - Готово! - Тестируем.
Я написал тест для двух вариантов, используя "std::" и не используя, выбирайте нужный вам.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Unicode.cpp: определяет точку входа для консольного приложения.
 
#include <fcntl.h>
#include <io.h>
#include <Windows.h>
#include <iostream>
#include <sstream>
 
int wmain(int argc, wchar_t* argv[], wchar_t *envp[]) //https://msdn.microsoft.com/ru-ru/library/bky3b5dh.aspx?f=255&MSPPError=-2147217396
{   ////////////////////Переводим в Юникод
    _setmode(_fileno(stdout), _O_U16TEXT); // https://msdn.microsoft.com/ru-ru/library/tw4k6df8.aspx
    _setmode(_fileno(stdin), _O_U16TEXT);
    _setmode(_fileno(stderr), _O_U16TEXT);
    ////////////////////Меняем размер консоли - можно пропустить, если вам не надо
    system("mode con cols=100 lines=50"); //размер окна, вывод нужного количества строк в консоль (видимых)
    HANDLE  hout = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD  size{ 100,100 };//символов строки, строк (если больше чем видимых, скрываются под ползунком прокрутки)
    SetConsoleScreenBufferSize(hout, size);//размер буфера
    ////////////////////Меняем шрифт для отображения символов Unicode, можно пропустить - если у вас установлен нужный
    CONSOLE_FONT_INFOEX cfi; //https://docs.microsoft.com/en-us/windows/console/console-font-infoex
    cfi.cbSize = sizeof(CONSOLE_FONT_INFOEX);
    cfi.nFont = 0;
    cfi.dwFontSize.X = 8;
    cfi.dwFontSize.Y = 14;
    cfi.FontFamily = FF_DONTCARE;
    cfi.FontWeight = FW_NORMAL;//400;
    wcscpy_s(cfi.FaceName, L"Lucida Console");
    SetCurrentConsoleFontEx(hout, false, &cfi);
    ////////////////////
 
    //Тест
    wchar_t* wchar_C = new wchar_t[255];
    //или
    std::wstring wstring_cpp;
 
    wprintf(L"%s", L"Testing unicode -- English -- Русский -- Ελληνικά -- Español.\n");
    // или
    std::wcout << L"Testing unicode -- English -- Русский -- Ελληνικά -- Español." << std::endl;
    
    //далее
    wprintf(L"%s", L"Введите строку с пробелами (разными символами, разной раскладки)(C): \n");
    fgetws(wchar_C, 255, stdin); //забираем строку с пробелами
    wchar_C[wcscspn(wchar_C, L"\n")] = 0; //убираем перевод строки
    wprintf(L"%s", wchar_C); //выводим
    //или
    std::wcout << L"\nВведите строку с пробелами (разными символами, разной раскладки)(C++std::): \n";
    std::getline(std::wcin, wstring_cpp); //забираем строку с пробелами
    std::wcout << wstring_cpp + L"\n"; //выводим
 
    system("pause");//пауза для просмотра результата
    return 0;
}
Использованные ресурсы:
Кликните здесь для просмотра всего текста
https://msdn.microsoft.com/ru-... 2147217396
https://msdn.microsoft.com/ru-... k6df8.aspx
https://docs.microsoft.com/en-... ont-infoex
обсуждение на stackoverflow, здесь ссылка рубится, не могу выложить


Мой репозиторий на GitHub

В итоге, см.рис.
Миниатюры
Нажмите на изображение для увеличения
Название: Console.PNG
Просмотров: 1178
Размер:	12.4 Кб
ID:	4538  
Размещено в Без категории
Показов 18041 Комментарии 19
Всего комментариев 19
Комментарии
  1. Старый комментарий
    Аватар для bedvit
    Должно быть так в коде:

    wprintf(L"%s", L"Testing unicode -- English -- Русский -- Ελληνικά -- Español.\n");
    // или
    std::wcout << L"Testing unicode -- English -- Русский -- Ελληνικά -- Español." << std::endl;


    Здесь, на сайте, в текст. редакторе С++ отображаются, видимо, не все знаки Юникода, о чем собственно говорится в Шаг.4 или кодировка не Unicode(UTF-16).
    Для этого комментария выбрал шрифт "Lucida Console".
    Запись от bedvit размещена 07.12.2017 в 13:24 bedvit вне форума
  2. Старый комментарий
    Аватар для Avazart
    UTF-16 ? Обычно исходники в UTF-8 так что стоило бы на него ориентироваться.

    С другой стороны стоит ли менять шрифт консоли, кодировку ипр. когда это можно сделать вне программы, например батником.
    Запись от Avazart размещена 07.12.2017 в 17:07 Avazart вне форума
    Обновил(-а) Avazart 07.12.2017 в 17:09
  3. Старый комментарий
    Аватар для bedvit
    Цитата:
    Сообщение от Avazart Просмотреть комментарий
    исходники в UTF-8
    Все верно, поэтому есть Шаг.3 - исходники в UTF-16. Ибо в противном случае, текст из исходников (в "const wchar_t") будет отражаться не верно, ведь типов wchar_t и char16_t, std::wstring - 16 битные.
    А UTF-8 (1-4 байта в зависимости от символа, насколько я знаю).
    Конечно, если вы работаете с char или std::string, то для ввода/вывода консоли нужно будет перейти на широкие символы, это не всегда удобно, но в моем случае это было несложно (проект маленький)
    Запись от bedvit размещена 07.12.2017 в 19:09 bedvit вне форума
  4. Старый комментарий
    Аватар для bedvit
    Сейчас посмотрел, если перейти на UTF-8 и проект и консоль
    _setmode(_fileno(stdout), _O_U8TEXT);
    _setmode(_fileno(stdin), _O_U8TEXT);
    _setmode(_fileno(stderr), _O_U8TEXT);
    Кириллицу не понимает, а жаль...
    Запись от bedvit размещена 07.12.2017 в 19:29 bedvit вне форума
  5. Старый комментарий
    Аватар для Avazart
    Цитата:
    Все верно, поэтому есть Шаг.3 - исходники в UTF-16.
    А смысл тогда? В таком уже случае может стоить проще использовать сp1251
    Запись от Avazart размещена 08.12.2017 в 20:23 Avazart вне форума
  6. Старый комментарий
    Аватар для bedvit
    сp1251 это русская ansi, в не локализованной win кириллица и прочие языки выводиться не будут. Чем удобен UTF-16: почти все символы 2 байта (4 только спец. китайский, музыкальные символы и прочая экзотика), wchar_t то же два байта, win на UTF-16 (api тоже) Все в одном размере, не нужно преобразований. Размер строки легко считается. Работает на любом win (кроме старокитайского) с вводом/отображением почти всех языков. Минусы - несколько большой объём занимаемой памяти.
    Запись от bedvit размещена 09.12.2017 в 00:07 bedvit вне форума
  7. Старый комментарий
    Аватар для Avazart
    Ansi это ansi, а cp1251 это как раз ее расширенная версия т.е ansi+кириллица.
    Если пишется под русскоязычную винду этого достаточно.

    Кстати у вас в коде только вывод символов, а ввод кириллицы проверяли, работает ?
    Запись от Avazart размещена 09.12.2017 в 00:20 Avazart вне форума
    Обновил(-а) Avazart 09.12.2017 в 00:25
  8. Старый комментарий
    Аватар для bedvit
    Windows-1251 (сp1251) это русская ansi (расширенная ascii, в которой часть символов, со 128-го, заменены/добавлены на русский алфавит и проч. символы), т.е. одна из разновидности набора ANSI, содержащая символы русского алфавита. Собственно поэтому и гемор с разными локализациями при использовании ANSI(локализованных) .
    Да, и ввод и вывод работает на русском и других языках, можете попробовать
    В приложенном рис. это строки 4-5, 7-8 (ввод-вывод).
    Запись от bedvit размещена 09.12.2017 в 21:54 bedvit вне форума
  9. Старый комментарий
    Аватар для Avazart
    Да только главную проблему это не решает (кодировка исходника нестандартная)
    Запись от Avazart размещена 10.12.2017 в 14:19 Avazart вне форума
  10. Старый комментарий
    Аватар для Avazart
    Кстати там UCS BE или LE ?
    Запись от Avazart размещена 10.12.2017 в 14:40 Avazart вне форума
  11. Старый комментарий
    Аватар для bedvit
    Да, шаг.3 необходим для данного решения. Сфера применения - или новые проекты или проекты, легко переходящие с UTF-8, на UTF-16 или для тех, кто и так пользуется wchar_t или std::wstring. Минусом - нужно больше памяти под проект и под строку. Плюсом - нормальная кодировка почти всех языков на всех win, любой локализации.
    Запись от bedvit размещена 10.12.2017 в 14:49 bedvit вне форума
  12. Старый комментарий
    Аватар для bedvit
    Для win родной Win (UTF-16LE), поэтому думаю LE.
    Запись от bedvit размещена 10.12.2017 в 14:51 bedvit вне форума
  13. Старый комментарий
    Аватар для Avazart
    Ну под линуксом исходники обычно в UTF-8 и используют char, std::string
    То сколько памяти нужно это дело последнее в наше время.
    Запись от Avazart размещена 10.12.2017 в 14:51 Avazart вне форума
    Обновил(-а) Avazart 10.12.2017 в 14:52
  14. Старый комментарий
    Аватар для bedvit
    Да и под win используют UTF-8 и используют char, std::string. Хотя больше чем под линуксом, используют и двухбайтовые wchar_t (TCHAR - пока не завоевал моего доверия ). Насколько я знаю, wchar_t в линуксе - 4х байтовый? (не работал в данной ОС)
    Запись от bedvit размещена 10.12.2017 в 15:45 bedvit вне форума
  15. Старый комментарий
    Аватар для Avazart
    wchar_t может плавать от платформы к платформе.
    Запись от Avazart размещена 10.12.2017 в 18:06 Avazart вне форума
  16. Старый комментарий
    Аватар для Замабувараев
    Высокоуровневые си плас плас функции.
    Если хотите низкоуровневую работу, то можно использовать WriteConsoleW.
    Запись от Замабувараев размещена 05.05.2018 в 14:34 Замабувараев вне форума
  17. Старый комментарий
    Все-таки переводить исходники в UTF-16 не нужно. Компилятор перекодирует строки, помеченные префиксом L.
    Файл в может быть спокойно в UTF-8, как общепринято.
    Запись от DrOffset размещена 28.06.2020 в 18:42 DrOffset вне форума
  18. Старый комментарий
    Аватар для bedvit
    DrOffset, Спасибо за корректировку. Все верно. Отметил этот момент в главном топике.
    Запись от bedvit размещена 26.10.2022 в 11:01 bedvit вне форума
  19. Старый комментарий
    Аватар для Замабувараев
    Круто конечно, но никак не могу отогнать от себя мысль что Си Плас Плас вместо программ создаёт Bloatware.
    На фрибесике такой екзешник займёт полтора‐два килобайта.
    А на Си Плас Плас сколько?
    Запись от Замабувараев размещена 26.10.2022 в 19:23 Замабувараев вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru