#include <conio.h>
#include <iostream>
#include <boost/locale.hpp>
using namespace boost::locale;
using namespace std;
int wmain()
{
generator gen;
locale loc=gen("ru_RU.UTF-8");
wcout.imbue(loc);
wcout<<L"Русский текст"<<endl;
_getch();
return 0;
}
Программа должна корректно выводить текст в консоли Windows в кодировке UTF-8.
Понятное дело что просто так она это не выводит.
Ставлю для cmd.exe шрифт Lucinda Console.
Ставлю кодировку — chcp 65001 (кодировка UTF-8).
Запускаю в полученной среде программу.
На экране либо пустота либо квадраты (Windows XP/7).
Делаю операцию
Test.exe >1.txt
type 1.txt
На экране:
Русский текст.
Что за нафиг? Как это лечить? Я хочу чтобы в самой программе вывод был нормальный.
L"Русский текст" — это действительно будет utf-16
В моём примере оно преобразуется внутри системных библиотек в utf-8 И плюётся на экран. type же отрабатывает правильно с выводом программы.
В том то и дело что хочу написать реально кросплатформенную программу, используя некое внутреннее представление строк и символов и кодировку utf-8 как выводную посредством boost.
Ибо на юниксе однобайтовые кодировки померли — остался utf-8.
А винду можно заставить работать в utf-8.
Задача стоит не в том чтобы написать ещё какой-то конвертер одной кодировки в другую (это не требуется — всё уже проделано до меня). Задача — в правильном отображении самого ВЫВОДА ПРОГРАММЫ, а не результатов складированных в файл.
Задача не в том чтобы вывести русский текст в консоль. Это и ребёнок сделает.
Задача стоит в том чтобы вывести utf-8 в консоль и она корректно отображалась(это при том что преобразование работает правильно — проверял, локаль консоли тоже правильно настроена).
Здравствуйте, sunheretic13, Вы писали:
S>Что за нафиг? Как это лечить? Я хочу чтобы в самой программе вывод был нормальный.
(Сижу не в винде, поэтому только по старой памяти могу сказать)
Во-первых, wcout отличается коварным поведением: он различает, подключен stdout непосредственно к консоли (utf-16) или к файлу/пайпу (поток байтов).
Соответственно, и конвертирует он туда или оттуда.
Не помню, обладает ли wprintf тем же свойством, или это специфика именно wcout (склоняюсь к последнему). За подробностями — смотри исходники стандартной библиотеки, в частности, ищи использование функции isatty.
Поэтому test.exe и test.exe>1.txt выполняют разную работу.
Во-вторых, в винде локали называются атипично: не ru_RU, а rus_RUS, он же Russian... Из-за неправильного названия setlocale может банально не сработать, и ты окажешься с дефолтной локалью вместо ожидаемой.
В-третьих, вайдовый литерал L"Русский текст" в сишном исходнике — записан в какой-то байтовой кодировке (как, собственно, и весь исходник).
Текстовый редактор считает, что это кодировка X (на ней "Русский текст" выглядит правильно); компилятор — что это кодировка Y. И именно из Y переводит в utf-16, чтобы поместить в секцию констант.
Чтобы кодировки редактора и компилятора совпадали, нужно или оставаться с дефолтными настройками (тогда они обе будут cp1251, скорее всего), или приложить какие-то дополнительные усилия (например, если кодировка редактора — utf-8...)
За подробностями — читать хелп по VisualStudio.
Как вся эта механика вместе может сглючить: чисто для примера, потому что сглючить она может разными способами.
1. Кодировка редактора — utf-8, компилятора — cp1251. L"Русский текст" с точки зрения компилятора выглядит как L"Р СѓСЃСЃРєРёР№ текст"
2. Локаль выбрать не удалось, она осталась системной
3. При выводе прямо в консоль получили мусор как есть
4. При выводе в файл мусор из utf-16 сконвертировали в cp1251, тем самым, восстановив старый utf-8 "Русский текст"
5. При распечатке файла — консоль переводит байты из кодировки 65001 в utf-16, и мы прекрасно видим "Русский текст"
Это мы разобрались, кого виновать. Теперь — что делать.
1) Отказаться от L-литералов. Ибо они сразу три беды вместе увязывают: кодировку редактора, компилятора и wcout'а.
Если очень хочется писать русский текст в литералах, а не в файлах переводов (когда программа маленькая и одноязычная, то морочиться с переводами не хочется) — то надо прибить гвоздями кодировку редактора и эту же кодировку упомятуть в setlocale в тексте программы.
2) Отказаться от wcout.
3) Про буст ничего не скажу, — только мне кажется, что он здесь излишний, достаточно было средств <locale>. Если только он не решает проблему альтернативных названий кодировок под виндами.
Здравствуйте, sunheretic13, Вы писали:
S>Задача не в том чтобы вывести русский текст в консоль. Это и ребёнок сделает. S>Задача стоит в том чтобы вывести utf-8 в консоль и она корректно отображалась(это при том что преобразование работает правильно — проверял, локаль консоли тоже правильно настроена).
Кстати, в качестве дополнительной проверки можно попробовать вывести хардкоднутые строки:
— L"\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442"
— "\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9 \xd1\x82\xd0\xb5\xd0\xba\xd1\x81\xd1\x82"
Тем самым мы удостоверимся, что, по крайней мере, связка редактор-компилятор не вмешалась.
И заодно, что оба преобразования — в utf-16 и в utf-8 — сработали корректно как для вывода в консоль, так и для вывода в файл.
К>1) Отказаться от L-литералов. Ибо они сразу три беды вместе увязывают: кодировку редактора, компилятора и wcout'а. К>Если очень хочется писать русский текст в литералах, а не в файлах переводов (когда программа маленькая и одноязычная, то морочиться с переводами не хочется) — то надо прибить гвоздями кодировку редактора и эту же кодировку упомятуть в setlocale в тексте программы.
Я имел в виду — писать текст в байтовых литералах, т.е. "Русский текст".
ЭЭх.
Задача как раз и стояла:
1. Разобраться с Boost.Locale .
2. Использовать кроссплатформенное именование локали вроде ru_RU.UTF-8 вместо того чтобы на Windows изголяться локалями в виде "Russian".
Вообщем попробовал следующее.
1. Попробовал вбить этот текст — L"\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9 \xd1\x82\xd0\xb5\xd0\xba\xd1\x81\xd1\x82"
Не помогло
2. Прочитал инструкцию — http://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/running_examples_under_windows.html Люди советуют файлы исходников сохранять в файлы utf-8 с BOM-заголовком.
Сделал. Проверял и с
cout<<"Русский текст"
и
wcout<<"Русский текст"
и
wcout<<L"Русский текст"
Ничего не работает.
Я сколняюсь к мысли что видимо команда Boost не до конца оттестировала эту часть библитеки, либо делает какие-то особые настройки в Windows не описанные в руководстве.
Видимо те локали что генерируются boost-библиотекой какие-то "неправильные" и не подходят для вывода в консоль. Наверно придётся писать в багрепорт Boost, ибо я совершенно не понимаю как заставить этот пример работать на Windows.
Здравствуйте, sunheretic13, Вы писали:
S>Задача как раз и стояла: S>1. Разобраться с Boost.Locale . S>2. Использовать кроссплатформенное именование локали вроде ru_RU.UTF-8 вместо того чтобы на Windows изголяться локалями в виде "Russian".
А обязательно нужно русскую локаль целиком подцепить? Может, достаточно ограничиться только выбором кодировки — ".utf-8"?
S>Ничего не работает.
А если вместо wcout.imbue(loc) делать std::locale::global(gen) ?
А если создавать локаль без буста, — std::locale loc(".utf-8") ?
Здравствуйте, sunheretic13, Вы писали:
S>Наверно стоит закрыть тему. S>Вердикт — Boost.Locale очень сырая часть библиотеки boost, не пригодная для использования в программах.
Видимо, да.
Проще сделать условную компиляцию: если под винды, то locale("rus_RUS.utf-8"), иначе ("ru_RU.utf-8").
Или просто locale(".utf-8"), что должно сработать повсеместно.