Как включить русский язык в си?

Локализация работает на вывод через printf, но когда считываешь значения с файла выводится кракозябра. С английскими буквами все норм, как лечится?
Голосование за лучший ответ
лечится использованием одной и той же кодировки текста как в консоли, так и в
компиляторе.
кодировку текстового файла тоже проверить нужно
DefПросветленный (32808) 1 год назад
У спрашивающего файл данных в левой кодировке
I MSN’sУченик (87) 1 год назад
поменял на A
I MSN’sУченик (87) 1 год назад
поменял на ANSI, заработало. Спасибо
> когда считываешь значения с файла выводится кракозябра
- Синхронизировать кодировку в файле данных и исходниках
- Если файл данных менять нельзя, то только гонять все строки из файла через перекодировщик.
Похожие вопросы
Как задать русский язык в c
Если программа при выводе на консоль использует кириллицу, то мы можем столкнуться с ситуацией, когда вместо кириллических символов будут отображаются непонятные знаки. Особенно это актуально для ОС Windows. И в этом случае необходимо явным образом задать текущую локаль (культуру) для вывода символов. В языке C++ это можно сделать с помощью встроенной функции setlocale() .
Итак, изменим код, который использовался в прошлых темах следующим образом:
#include int main()
Компиляция и запуск в ОС Windows может выглядеть следующим образом:
c:\cpp>g++ -std=c++20 -Wall -pedantic app.cpp -o app & app Р?С?РёР?РчС' Р?РёС?! c:\cpp>
Вместо ожидаемого текста я получаю какие-то непонятные символы. Теперь изменим код, применив функцию setlocale() :
#include int main()
Теперь для вывода данных на консоль вместо объекта std::cout применяется объект std::wcout , который предназначен для работы с символами Unicode. В данном случае предполагается, что кодировка самого файла — UTF-8. Кроме того, перед строкой указан символ L .
Повторно компилируем и запустим приложение:
c:\cpp>g++ -std=c++20 -Wall -pedantic app.cpp -o app & app Привет мир! c:\cpp>
На некоторых платформах, например, Ubuntu, мы можем не столкнуться с подобной проблемой. И в этом случае вызов функции setlocale просто не окажет никакого влияния.
Русский язык в C++
Лучший способ совершенствовать навыки программирования на том или ином языке – это создание консольного программного обеспечения. Такие приложения обычно позволяют изучать особенности и нюансы функций, методов и классов.
C++ – известный язык разработки. Он является своеобразным стандартом, подходящим для самых разных целей. Именно поэтому далее предстоит более подробно изучить консольные приложения на C++.
Особое внимание в статье будет уделено вводу в консоль русского языка. Данная операция иногда может вызывать некоторые трудности. Наиболее распространенная ситуация – некорректное отображение кириллицы при вводе/выводе. Исправить положение обычно можно за счет грамотной разработки.
Особенности работы с вводом
Компьютеры и другие вычислительные машины умеют работать только с числами. Для представления букв или символов требуется воспользоваться так называемой кодировкой. Это алгоритм, согласно которому символ или буква получают определенное число-идентификатор. Подобное явление привело к образованию таблиц кодирования символов.
В разработке под Windows (не только на C++, но и на других языках программирования) чаще всего предстоит иметь дело с кодированными таблицами:
- UTF-8 (стандарт Unicode);
- cp1251;
- cp866.
Универсальной кодировочной таблицей служит Unicode, но это не меняет того, что в операционных системах допускается использование сразу нескольких кодировочных таблиц. Именно из-за них при работе той или иной программы на экране вместо нужных элементов появляются разнообразные нераспознаваемые символы.
В Windows кодировка символов соответствует стандарту cp866. Для русскоязычных операционных систем от Microsoft используется стандартная таблица cp1251 8-бит. При вводе текста в консоль через программу C++ происходит преобразование кириллицы в стандарт cp866. В этом случае некоторые элементы могут быть интерпретированы неправильно. Чтобы исправить ситуацию, нужно грамотно перекодировать его в стандарт cp866.
Функция setlocale
Локаль – это некий набор параметров:
- символы;
- страна;
- часовой пояс;
- язык пользователя;
- другие элементы.
Данный компонент в программном коде требуется для быстрой настройки пользовательского интерфейса в зависимости от географического положения.
C++ имеет функцию setlocale. Она используется для перекодировки символов в соответствие с требуемым языком. Данная функция определяется в заголовочном файле .
Функция setlocale имеет несколько параметров:
- тип категории локали;
- значение локали.
Для настройки русской консоли в C программе требуется воспользоваться локалью «rus». Вместо аргумента «rus» допускается написание «Russian» в рассматриваемой функции. Оставлять двойные кавычки пустыми допустимо, если символьный набор будет совпадать с параметрами имеющейся операционной системы.
Особенности Setlocale
Setlocale 0 rus – функция, которая задает локаль, используемую текущей программой. Она встречается в C и C++. Заголовочными файлами соответственно будут служить:
- locale.h – для Си;
- clocale – для C++.
Текущую локаль можно получить, передав через параметр locale значение NULL. Прототип функции имеет следующую форму:
- LC_ALL – вся локаль;
- lc_collate – оказывает влияние на strcoll и strfrm;
- lc_ctype – оказывает влияние на поведение всех команд заголовочного файла cctype за исключением isdigit и isxdigit;
- lc_monetary – денежный формат;
- lc_numeric – влияет на десятичную точку ввода/вывода и на команды форматирования строк;
- lc_time – изменяет поведение команды strftime.
Параметр locale включает в себя имя локали. Сюда можно передать минимум два значения: «C» – минимальную Си-локаль и » « – локаль по умолчанию, используемую средой разработки. Другие параметры тоже могут передаваться. Пример – для распознавания кириллицы.
Способы решения проблемы с вводом данных
Функция setlocale в C++ работает только для потока вывода. При использовании setlocale для ввода данных в консоль на экране появляются все те же непонятные символы. Вот пример работы приложения с вводом кириллицы. Здесь строка данных сохраняется в переменную, после чего выводится на консоль:
Выше можно заметить результат реализации фрагмента кода. Слово «Вывод» отобразилось корректно, а содержимое строки string – нет. Такое случилось из-за того, что setlocale работает только с потоком ввода.
Для исправления ситуации можно подключить заголовочный файл windows.h. В нем имеются прототипы функций SetConsoleCP и SetConsoleOutputCP. Они заменяют setlocale. Аргументом для рассматриваемых функций служит идентификатор кодовой страницы – win-cp 1251. SetConsoleCP используется для установки нужной таблицы на ввод (заменяет setlocale), SetConsoleOutputCP работает непосредственно с выводом.
У данного приема имеется один недостаток – указанные функции умеют работать только со шрифтом Lucida Console. По умолчанию в консоли установлен шрифт Consolas. Это приводит к тому, что в командной строке нужно предварительно настроить используемый тип шрифта. Для этого нужно:
- Открыть CMD в Windows.
- Перейти в «Свойства».
- Во вкладке «Шрифт» выбрать Lucida Console.
- Нажать на «Ок».
Если все сделано верно, кириллица будет работать корректно. Вот пример, в котором вместо setlocale используются предложенные ранее команды:
Ввод и вывод на кириллице в C++ настроены. Лучше разбираться в include locale.h и кодировках помогут специальные компьютерные курсы .
Русский язык в консоли
«Повторяющееся слово: » — отображается нормально благодаря setlocale. То что после — крякозяблы, хотя повторяющееся слова находит. setlocale пробовал разные (0, «»), «», «Rus» и пр. В Code::Blocks всё работает и без крякозяблов. Даже без setlocale.
Отслеживать
20.2k 6 6 золотых знаков 37 37 серебряных знаков 81 81 бронзовый знак
задан 17 окт 2015 в 14:52
711 1 1 золотой знак 6 6 серебряных знаков 3 3 бронзовых знака
увы, но setlocale Вас не спасёт, единственный вариант нормальный это сменить кодировку в консоли
17 окт 2015 в 15:00
Найдите дубликат, кто-нибудь!
17 окт 2015 в 16:46
@VladD, нашёл пример с CharToOem, вполне годно ru.stackoverflow.com/questions/70089/…
18 окт 2015 в 2:05
@VladD о, нашел — ru.stackoverflow.com/a/434186/177221 — это работающий вариант именно для Visual Studio. Ваш ответ там тоже есть, кстати. Предлагаю переоткрыть и сделать из этого вопроса каноничный. Потому что CP1251 — это какая-то жесть.
– user177221
18 окт 2015 в 11:40
@Umed, это вопрос с пятью минусами, а не пример. Минусы там за последний UPD автора и к тому же Ваш charToOem и ConsoleCP там тоже есть. Видимо вы даже не удосужились нормально просмотреть скинутую ветку, увы.
18 окт 2015 в 19:38
5 ответов 5
Сортировка: Сброс на вариант по умолчанию
Для данной задачи существует множество решений. Если вам нужно быстрое и не обязательно универсальное решение, чтобы сильно не разбираться, прокручивайте к разделу «Менее правильные, но пригодные решения».
Правильное, но сложное решение
Для начала, проблема у консоли Windows состоит в том, что её шрифты, которые стоят «по умолчанию», показывают не все символы. Вам следует сменить шрифт консоли на юникодный, это позволит работать даже на английской Windows. Если вы хотите поменять шрифт только для вашей программы, в её консоли нажмите на иконку в левом верхнем углу → Свойства → Шрифт. Если хотите поменять для всех будущих программ, то же самое, только заходите в Умолчания, а не Свойства.
Lucida Console и Consolas справляются со всем, кроме иероглифов. Если ваши консольные шрифты позволят, вы сможете вывести и 猫 , если нет, то лишь те символы, которые поддерживаются.
Дальнейшее рассмотрение касается лишь Microsoft Visual Studio. Если у вас другой компилятор, пользуйтесь предложенными на свой страх и риск, никакой гарантии нету.
Теперь, кодировка входных файлов компилятора. Компилятор Microsoft Visual Studio (по крайней мере, версии 2012 и 2013) компилирует исходники в однобайтных кодировках так, как будто бы они на самом деле в ANSI-кодировке, то есть для случая русской системы — CP1251. Это означает, что кодировка исходников в CP866 — неправильна. (Это важно, если вы используете L». » -строки.) С другой стороны, если вы храните исходники в CP1251, то эти же исходники не будут нормально собираться на нерусской Windows. Поэтому стоит хранить исходники в Unicode (например, UTF-8).
Настроив среду, перейдём к решению собственно задачи.
Правильным решением является уйти от однобайтных кодировок, и использовать Unicode в программе. При этом вы получите правильный вывод не только кириллицы, но и поддержку всех языков (изображение отсутствующих в шрифтах символов будет отсутствовать, но вы сможете с ними работать). Для Windows это означает переход с узких строк ( char* , std::string ) на широкие ( wchar_t* , std::wstring ), и использование кодировки UTF-16 для строк.
(Ещё одна проблема, которую решает использование широких строк: узкие строки при компиляции кодируются в однобайтную кодировку используя текущую системную кодовую страницу, то есть, ANSI-кодировку. Если вы компилируете вашу программу на английской Windows, это приведёт к очевидным проблемам.)
Вам нужно _setmode(_fileno(. ), _O_U16TEXT); для переключения режима консоли:
#include #include #include int wmain(int argc, wchar_t* argv[]) < _setmode(_fileno(stdout), _O_U16TEXT); _setmode(_fileno(stdin), _O_U16TEXT); _setmode(_fileno(stderr), _O_U16TEXT); std::wcout
Такой способ должен работать правильно с вводом и выводом, с именами файлов и перенаправлением потоков.
Важное замечание: потоки ввода-вывода находятся либо в «широком», либо в «узком» состоянии — то есть, в них выводится либо только char* , либо только wchar_t* . После первого вывода переключение не всегда возможно. Поэтому такой код:
cout
вполне может не сработать. Используйте только wprintf / wcout .
Если очень не хочется переходить на Unicode, и использовать однобайтную кодировку, будут возникать проблемы. Для начала, символы, не входящие в выбранную кодировку (например, для случая CP1251 — базовый английский и кириллица), работать не будут, вместо них будет вводиться и выводиться абракадабра. Кроме того, узкие строковые константы имеют ANSI-кодировку, а это значит, что кириллические строковые литералы на нерусской системе не сработают (в них будет зависимая от системной локали абракадабра). Держа в голове эти проблемы, переходим к изложению следующей серии решений.
Менее правильные, но пригодные решения
В любом случае, поставьте юникодный шрифт в консоли. (Это первый абзац «сложного» решения.)
Убедитесь, что ваши исходники в кодировке CP 1251 (это не само собой разумеется, особенно если у вас не русская локаль Windows). Если при добавлении русских букв и сохранении Visual Studio ругается на то, что не может сохранить символы в нужной кодировке, выбирайте CP 1251.
(1) Если компьютер ваш, вы можете поменять кодовую страницу консольных программ на вашей системе. Для этого сделайте вот что:
- Запустите Regedit.
- На всякий пожарный экспортируйте куда-нибудь реестр (этот шаг все почему-то пропускают, так что когда всё сломается, мы вас предупреждали).
- В разделе HKEY_CURRENT_USER\Console найдите ключ CodePage (если нету, создайте ключ с таким названием и типом DWORD ).
- Установите значение по ключу (левая клавиша/изменить/Система счисления = десятичная) на 1251.
- Не забудьте перегрузиться после изменений в реестре.
Преимущества способа: примеры из книг начнут работать «из коробки». Недостатки: смена реестра может повлечь за собой проблемы, кодировка консоли меняется глобально и перманентно — это может повлиять сломать другие программы. Плюс эффект будет только на вашем компьютере (и на других, у которых та же кодировка консоли). Плюс общие проблемы неюникодных способов.
Примечание. Установка глобальной кодовой страницы консоли через параметр реестра HKEY_CURRENT_USER\Console\CodePage не работает в Windows 10, вместо него будет использована кодовая страница OEM - предположительно баг в conhost. При этом установка кодовой страницы консоли на уровне конкретного приложения ( HKEY_CURRENT_USER\Console\(путь к приложению)\CodePage ) работает.
(2) Вы можете поменять кодировку только вашей программы. Для этого нужно сменить кодировку консоли программным путём. Из вежливости к другим программам не забудьте потом вернуть кодировку на место!
Это делается либо при помощи вызова функций
SetConsoleCP(1251); SetConsoleOutputCP(1251);
в начале программы, либо про помощи вызова внешней утилиты
system("chcp 1251");
(То есть, у вас должно получиться что-то вроде
#include int main(int argc, char* argv[]) < std::system("chcp 1251"); .
#include int main(int argc, char* argv[]) < SetConsoleCP(1251); SetConsoleOutputCP(1251); .
и дальше обыкновенный код программы.)
Можно обернуть эти вызовы в класс, чтобы воспользоваться плюшками автоматического управления временем жизни объектов C++.
#include #include int chcp(unsigned codepage) < // составить команду из кусочков std::string command("chcp "); command += codepage; // выполняем команду и возвращаем результат return !std::system(command.c_str()); >// этот код будет запущен перед main static int codepage_is_set = chcp(1251);
(если выполняете задание из Страуструпа можно вставить в конец заголовочного файла std_lib_facilities.h )
#include class ConsoleCP < int oldin; int oldout; public: ConsoleCP(int cp) < oldin = GetConsoleCP(); oldout = GetConsoleOutputCP(); SetConsoleCP(cp); SetConsoleOutputCP(cp); >// поскольку мы изменили свойства внешнего объекта — консоли, нам нужно // вернуть всё как было (если программа вылетит, пользователю не повезло) ~ConsoleCP() < SetConsoleCP(oldin); SetConsoleOutputCP(oldout); >>; // и в программе: int main(int argc, char* argv[])
Если вам нужен не русский, а какой нибудь другой язык, просто замените 1251 на идентификатор нужной кодировки (список указан ниже в файле), но, разумеется, работоспособность не гарантируется.
Остались методы, которые тоже часто встречаются, приведём их для полноты.
Методы, которые работают плохо (но могут помочь вам)
Метод, который часто рекомендуют — использование конструкции setlocale(LC_ALL, "Russian"); У этого варианта (по крайней мере в Visual Studio 2012) гора проблем. Во-первых, проблема с вводом русского текста: введённый текст передаётся в программу неправильно! Нерусский текст (например, греческий) при этом вовсе не вводится с консоли. Ну и общие для всех неюникодных решений проблемы.
Ещё один метод, не использующий Unicode — использование функций CharToOem и OemToChar . Этот метод требует перекодировки каждой из строк при выводе, и (кажется) слабо поддаётся автоматизации. Он также страдает от общих для неюникодных решений недостатков. Кроме того, этот метод не будет работать (не только с константами, но и с runtime-строками!) на нерусской Windows, т. к. там OEM-кодировка не будет совпадать с CP866. В дополнение можно так же сказать что эти функции поставляются не со всеми версиями Visual Studio — например в некоторых версиях VS Express их просто нет.
- Как выводить на экран и вводить данные типа wchar_t[]?
- к сожалению, автор того вопроса пользовался компилятором MinGW под Cygwin и WinXP, что делает большинство современных решений неприменимыми.
- Output unicode strings in Windows console app
- Conventional wisdom is retarded, aka What the @#%&* is _O_U16TEXT?
- What's the difference between printf(“%s”), printf(“%ls”), wprintf(“%s”), and wprintf(“%ls”)?
- Русский язык в исходном коде в Dev C++
- Code Page Identifiers