Страницы, Java, C#

суббота, 17 марта 2012 г.

C++. Кириллица в консоли и файлах.

Обычно для работы с кириллицей мне всегда хватало следующего способа
#include "stdafx.h"
#include <iostream>
#include <locale>

int _tmain(int argc, _TCHAR* argv[])
{
 setlocale(LC_ALL,"Russian");
 std::cout<<"Проверка на поддержку кириллицы\n";
 system("pause");
 return 0;
}

Суть которого была в том, что мы впихиваем хеадер locale и прописываем в начале программы setlocale(LC_ALL,"Russian"). Недостаток этого метода в том, что на cout всё и заканчивается. Этот метод не дает корректной работы с вводом кириллических символов из консоли и недаёт их корректного сохранения в файл.

Но тут мне неожиданно сорвало крышу и я решил немного углубиться в эту тему. Различные CharToOem, OemToChar мне как-то не пришлись по душе. И тут я узнал о такой прекрасной вещице как широкие (wide) потоки. Это потоки, которые работают с широкими символами (тот самый wchar_t).

Ближе к сути, пример кода поддерживающего кириллицу:

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string> //если нужны строки string

int _tmain(int argc, _TCHAR* argv[])
{
 //проверим консольный ввод вывод
 //а также хранение кириллицы в расширенных строках
 std::wcout.imbue(std::locale("rus_rus.866"));
 std::wcin.imbue(std::locale("rus_rus.866"));
 std::wcout<<L"Тест вывода кириллицы в консоль\n\n";
 std::wcout<<L"Введите что-либо по-русски:";
 std::wstring str=L"";
 std::wcin>>str;
 std::wcout<<L"Вы ввели: "<<str<<L"\n";
 //проверим файловые потоки
 std::wfstream fout;
 fout.open(L"тест-файл.txt",std::ios::out);
 if(fout.is_open())
 {
  fout.imbue(std::locale("rus_rus.1251"));//а здесь, кодировка 1251
  fout << L"Тест на поддержку кириллицы\n";
  std::wcout<<L"\nТакже проверьте файл тест-файл.txt\n";
  fout.close();

 }
 system("pause");
 return 0;
}

Как видите, с помощью расширенных потоков решаются все проблемы локализации. Сама установка языка и кодировки происходит (барабанная дробь) с помощью потокового метода imbue(std::local("language_country")).

Давайте посмотрим, что за строку мы помещаем. В строке "rus_rus.866" первое вхождение rus устанавливает поддержку русского языка, второе вхождение rus означает страну, где всё это мы собираемся использовать.Число строка ".866" - кодировка. Заметьте что для вывода на консоль мы используем  кодировку 866, а для вывода в файл кодировку 1251. Таким образом, если бы мы были французами и нам было бы нужно обеспечит поддержку французского языка, а по поводу кодировки вообще бы не парились, тогда бы мы прописали следующий параметр locale( "french_france" ). 

Перед каждой строкой стоит специальный модификатор L"некая строка". И если где-либо появились кракозябры, то в первую очередь следует посмотреть наличие этого модификатора.

Теперь о самих потоках. Для работы с консолью, вместо привычных cout и cin здесь используются wcout и wcin. Приставка w от англ. wide - широкий, означает что эти операторы предназначены для работы с широкими символами. Для работы с файлами, потоки, к примеру можно задать следующими способами:

std::wfstream fout;//просто файловый поток
std::wifstream fout;//входной файловый поток(для чтения из файла)
std::wofstream fout;//выходной файловый поток
std::wofstream fout("файл.txt");//тот же выходной поток, но с привязкой к файлу

Как видите, правила использования широких потоков такие же что и для использования обычных.

Итак, мы получаем метод
  • который является чистым с++-методом
  • а значит, уменьшается вероятность аппаратных неурядиц, характерных для чистого си.
  • который элегантен, в отличие от различного рода CharToOem и т.д.
  • который является универсальным, вотличие от setlocale()
  • и является по сути использованием готового решения, а значит меньше отвлекаться от основной задачи

Для более подробного ознакомления рекомендую:
http://www.rsdn.ru/forum/cpp/1854733.1.aspx

1 комментарий:

  1. В строке
    fout << L"Тест на поддержку кириллицы\n";
    мы явно объявляем ту строку, которую хотим записать в файл. Как быть, если у меня необходимая информация хранится в переменной buff типа char?
    fout<< buff; - не помогает. Заранее спасибо!

    ОтветитьУдалить