Rating@Mail.ru

Форум сайта "Виртуальная энциклопедия "Linux по-русски"


Текущее время: 27 апр 2017, 14:02

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 18 ]  На страницу 1, 2  След.
Автор Сообщение
Непрочитанное сообщениеДобавлено: 22 мар 2013, 17:10 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Вопрос связан с соседней темой: исполнение Windows промышленных проектов под Wine.

Состоит он вот в чём:
- создадим (напишем) платформенно независимое консольное приложение ... "Привет мир!" :lol:
- на С или С++ ... используя либо Boost (как в теме откуда переплыл вопрос), или Apache Portable Runtime (APR) ... , или любой инструмент переносимого программирования - проблема будет наблюдаться везде!
- но в программе будут выводиться русскоязычные строки:
Код:
std::cout <<  "Привет мир!" << std::endl;

- такая программа в Linux будет нормально (ожидаемо) исполняться, т.к. в современном Linux и редакторы кода (или IDE разработки) и терминал работают в UTF-8 (Unicode);
- если перенести такое приложение в MS Visual Studio (а для чего мы тогда уродовались с Boost? ;-) ) + добиться нормальной сборки проекта (указанием путей инклудов и бинарных библиотек Boost), то программа может быть скомпилирована...
- но при запуске её в консоли - получим кракозябры ... текст UTF-8, который прекрасно видится как надо в редакторе MS Visual Studio, при выводе в тупую Windows консоль, ожидающую свою уродливую кодировку CP-1251, отображается бредовым набором символов.

Как?

Проблема здесь не в переносимости UNIX <-> Windows, проблема здесь чисто Windows, потому как если такое приложение "Привет мир!" набить в пустом консольном проекте Windows, то получится такое же уродство. Но меня мало занимают проблемы разбирательства с Windows-уродствами ... пусть они "сами хоронят своих мертвецов".

Вопрос маленький и конкретный, состоящий в том: как запустить консольное приложение в Windows с отображением русского текста?
И с тем, чтобы явно в код не вписывать всякие Windows-ные штучки-дрючки, по типу явного преобразования строк в CP-1251 ... что не будет работать ни в одной другой системе.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 22 мар 2013, 17:31 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Olej писал(а):
Проблема здесь не в переносимости UNIX <-> Windows, проблема здесь чисто Windows, потому как если такое приложение "Привет мир!" набить в пустом консольном проекте Windows, то получится такое же уродство. Но меня мало занимают проблемы разбирательства с Windows-уродствами ... пусть они "сами хоронят своих мертвецов".

Вопрос маленький и конкретный, состоящий в том: как запустить консольное приложение в Windows с отображением русского текста?


Вот такой "родной" (никто никуда не переносился) проект VisualStudio, свеже набранный - ruscons1, исходный код ruscons1.cpp выглядит так:
Код:
#include "stdafx.h"

#include <iostream>
using namespace std;

int _tmain( int argc, _TCHAR* argv[] ) {
   cout << "Выводится русский текст" << endl;
   return 0;
}


А результат его выполнения в консоли выглядит так :twisted: :
Код:
C:\Documents and Settings\olej\Мои документы\Visual Studio 2010\Projects\ruscons1\Debug>ruscons1.exe
┬√тюфшЄё  Ёєёёъшщ ЄхъёЄ


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 22 мар 2013, 20:47 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Что они начудили там в Windows с локализациями я понять не могу!

Делаем проект такой (для проверки локализаций):
Код:
#include <iostream>
using namespace std;

int main( int argc, char* argv[] ) {
   cout << "russian string: Выводится русский текст" << endl;
   // locale::global( locale( "" ) );
   cout << "russian string: После глобальных системных установок" << endl;
   cout << "old locale: " << cout.getloc().name().c_str() << endl;
   while( true ) {
      char s[ 40 ];
      cout << "new locale: " << flush;
      cin >> s;
      locale loc;
      try { loc = locale( (char*)s ); }
      catch( runtime_error ) {
         cout << "wrong locale" << endl;
         continue;
      }
      // cout.imbue( loc ); // это не работает!
      locale::global( loc );
      cout << "russian string: Выводится русский текст" << endl;
   }
   return 0;
}


Результатов его я не понимаю:
Код:
C:\Documents and Settings\olej\Мои документы\Visual Studio 2010\Projects\ruscons1\Debug>ruscons1.exe
russian string: ┬√тюфшЄё  Ёєёёъшщ ЄхъёЄ
russian string: ╧юёых уыюсры№э√ї ёшёЄхьэ√ї єёЄрэютюъ
old locale: C
new locale: POSIX
wrong locale
new locale: en_US
wrong locale
new locale: ru_RU
wrong locale
new locale: English_USA.1252
russian string: Выводится русский текст
new locale: Russian
russian string: Выводится русский текст
new locale: Ukrainian
russian string: Выводится русский текст
new locale: German
russian string: Выводится русский текст
new locale:
^C

Человеческих локалей: POSIX, en_US, ru_RU - у них нет, есть какие-то уродства: English_USA.1252 и т.д.

Но вот той строчки закомментированной, похоже, достаточно для установки дефаултной локали, которая у меня в системе русская:
Код:
   locale::global( locale( "" ) );


Можно, конечно, использовать Boost систему локализации: Using Boost.Locale, но это пока никак не есть предметом моих интересов ;-)


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 22 мар 2013, 21:56 
Не в сети
Писатель

Зарегистрирован: 14 июн 2012, 06:01
Сообщения: 248
Может не в тему, просто увидел знакомые буквы...
Я когда-то решил как-то так http://goodluck.uzelok.net/archives/55
Если что это тоже мой ресурс :-)


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 23 мар 2013, 00:24 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
cema писал(а):
Может не в тему, просто увидел знакомые буквы...
Я когда-то решил как-то так http://goodluck.uzelok.net/archives/55


Там:
Цитата:
Первый способ заключается в том, что бы после написания программы сохранить файлы в кодировке OEM. Сделать это можно в блокноте, например Bred или Notepad 2. Просто открываете файл и сохраняете в DOS кодировке.
Второй способ - это воспользоваться файлами CyrIOS.cpp и CyrIOS.h, скачать их можно тут.
Просто добавьте эти файлы в проект и в файле проекта допишите:
#include “CyrIOS.h”

Это то, что будет работать в Windows, но моментально перестанет работать при перенесении кода без внесения изменений в Linux (или ещё куда-то). 1-й способ для этого совсем не уместный, а 2-й ... посмотрю что там позже. ;-)


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 23 мар 2013, 10:44 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Olej писал(а):
Это то, что будет работать в Windows, но моментально перестанет работать при перенесении кода без внесения изменений в Linux (или ещё куда-то).


Посмотрел мельком что делают Windows-программисты в этом случае - это полный бред!: они начинают преобразовывать строку перед выводом используя ChatToOem() ... а то и вообще ковыряя вручную коды символов :-o

Кое-что о причине того ужаса, который происходит с кодировками в Windows, описано здесь: Кириллица в консоли... хотя сама статья полна ошибок, хоть это и сайт "Учебники":
Цитата:
toefl, ielts, gre, gmat Унікальна методика підготовки

... действительно "уникальная" :-o
Вот как бывает, если смотреть на природу вещей с "Windows колокольни" :lol:

Удивляет то, что состояние дел этих в Windows противоречит такими стандартными понятиями языка С++ как: локаль, локализация, locale, ...


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 23 мар 2013, 13:28 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Программа, которая позволяет хоть как-то разобраться в этом идиотизме + просмотреть как в Windows записываются имена (символьные) локалей (которые у них пишутся совершенно не как у людей):
Код:
#include <clocale>
#include <iostream>

using namespace std;

int main( int argc, char* argv[] ) {
   cout << "russian string: Выводится русский текст" << endl;
   cout << "default locale: " << locale( "" ).name().c_str() << endl;
   cout << "old cout.locale: " << cout.getloc().name().c_str() << endl;
   while( true ) {
      char s[ 40 ];
      cout << "new locale: " << flush;
      cin >> s;
      locale loc;
      try { loc = locale( (char*)s ); }
      catch( runtime_error ) {
         cout << "wrong locale" << endl;
         continue;
      }
      cout.imbue( loc );
      cout << "cout.locale : " << cout.getloc().name().c_str() << endl;
      locale::global( loc );
      cout << "locale : " << std::setlocale( LC_ALL, NULL ) << endl;
      cout << "russian string: Выводится русский текст" << endl;
   }
   return 0;
}


Её выполнение:
Код:
russian string: ┬√тюфшЄё  Ёєёёъшщ ЄхъёЄ
default locale: Russian_Russia.1251
old cout.locale: C
new locale: Russian
cout.locale : Russian_Russia.1251
locale : Russian_Russia.1251
russian string: Выводится русский текст
new locale: Russian_Russia.65001
wrong locale
new locale: Russian_Russia.28595
cout.locale : Russian_Russia.28595
locale : Russian_Russia.28595
russian string: Т?тюфш?ё? №?ёёъшщ ?хъё?
new locale: Russian_Russia.20866
cout.locale : Russian_Russia.20866
locale : Russian_Russia.20866
russian string: бШБНДХРЯЪ ПСЯЯЙХИ РЕЙЯР
new locale: C
cout.locale : C
locale : C
russian string: ┬√тюфшЄё  Ёєёёъшщ ЄхъёЄ
new locale:


Откуда берётся вот этот идиотизм в записи? типа: Russian_Russia.20866
А это - KOI-8r :-o
Не ожидали? :lol:
А вот где в Windows мы его находим:
Вложение:
locale.GIF
locale.GIF [ 55.35 КБ | Просмотров: 6454 ]


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 23 мар 2013, 13:56 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Olej писал(а):
Откуда берётся вот этот идиотизм в записи? типа: Russian_Russia.20866
А это - KOI-8r :-o
Не ожидали? :lol:
А вот где в Windows мы его находим:


1. Я проделал это всё в Windows XP, но, предполагаю, что всякие прочие: WIndows 7, WIndows 8 (9, 10 и 11 :lol: ) - недалеко ушли! :evil:

2. Картина, в общем, понятная:

- вызовом вида loc = locale( "Russian_Russia.20866" ) можно создать новую локаль (переменную)...

- дальше можете или установить эту локаль для своей программы целиком ( locale::global( loc ) ), или для потока вывода ( cout.imbue( loc ) ) ... или для ввода и т.д.

- в Windows имена локалей (текстовая строка!) называются совершенно по-идиотски ... в отличие от всех нормальных людей ;-) - "Russian_Russia.20866" - это русская кодировка KOI-8r ...

- а у нормальных людей (в UNIX, в описаниях С++ у Б.Страуструпа, POSIX / IEEE Std 1003.1-2001) эти локали именуются по типу: "en_US.UTF-8", "de_DE.UTF-8", "ru_RU. ISO-8859-5"
Код:
bash-4.2$ set | grep LANG
LANG=ru_RU.UTF-8

Код:
bash-4.2$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=

См.: man (1P) locale, man (1P) localedef


- для того, чтобы в консоль Windows шёл нормальный русский вывод, нужно установить:
Код:
locale::global( locale( "Russian_Russia.1251" ) );

или
Код:
cout.imbue( locale( "Russian_Russia.1251" ) );

или, если это С, а не С++ :
Код:
setlocale( LC_ALL, "Russian_Russia.1251" )

Это плохо, потому, что это сработает в Windows, но не будет работать при переносе в UNIX.

- но если операционная система локализована, русскоязычная (установлены переменные окружения?), то достаточно и там и там (Linux, Windows) установить для программы локализацию системы (дефаултную):
Код:
locale::global( locale( "" ) );


Вот это к вопросу переносимости консольных программ между Linux и Windows, похоже, проблему полностью решает.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 23 мар 2013, 14:11 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Olej писал(а):
- а у нормальных людей (в UNIX, в описаниях С++ у Б.Страуструпа, POSIX / IEEE Std 1003.1-2001) эти локали именуются по типу: "en_US.UTF-8", "de_DE.UTF-8", "ru_RU. ISO-8859-5"
Код:
bash-4.2$ set | grep LANG
LANG=ru_RU.UTF-8



Кстати, интересно, вот что происходит, если в Linux изменить дефаултные установки языка, которые потянут и изменение locale:
Код:
bash-4.2$ export LANG=ru_RU.1251

bash-4.2$ set | grep LANG
LANG=ru_RU.1251

bash-4.2$ locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=ru_RU.1251
LC_CTYPE="ru_RU.1251"
LC_NUMERIC="ru_RU.1251"
LC_TIME="ru_RU.1251"
LC_COLLATE="ru_RU.1251"
LC_MONETARY="ru_RU.1251"
LC_MESSAGES="ru_RU.1251"
LC_PAPER="ru_RU.1251"
LC_NAME="ru_RU.1251"
LC_ADDRESS="ru_RU.1251"
LC_TELEPHONE="ru_RU.1251"
LC_MEASUREMENT="ru_RU.1251"
LC_IDENTIFICATION="ru_RU.1251"
LC_ALL=

bash-4.2$ ./randwr
terminate called after throwing an instance of 'std::runtime_error'
  what():  locale::facet::_S_create_c_locale name not valid
Аварийный останов (core dumped)


Код:
bash-4.2$ export LANG=ru_RU.UTF-8

bash-4.2$ ./randwr
Запуск:  ./randwr файл [число записей] [размер блока записи[{K,M}]]


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Непрочитанное сообщениеДобавлено: 23 мар 2013, 17:02 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9196
Откуда: Харьков
Olej писал(а):
- но если операционная система локализована, русскоязычная (установлены переменные окружения?), то достаточно и там и там (Linux, Windows) установить для программы локализацию системы (дефаултную):
Код:
locale::global( locale( "" ) );



Интересно, что в качестве имени языка/локали можно в переменных окружения записать любую ерунду:
Код:
bash-4.2$ export LANG=ru_RU.zzz

Это, естественно, в Linux + bash ... для которых ru_RU.1251 точно такая же ерунда, как и ru_RU.zzz.

И local подхватит это определение:
Код:
bash-4.2$ locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=ru_RU.zzz
LC_CTYPE="ru_RU.zzz"
LC_NUMERIC="ru_RU.zzz"
LC_TIME="ru_RU.zzz"
LC_COLLATE="ru_RU.zzz"
LC_MONETARY="ru_RU.zzz"
LC_MESSAGES="ru_RU.zzz"
LC_PAPER="ru_RU.zzz"
LC_NAME="ru_RU.zzz"
LC_ADDRESS="ru_RU.zzz"
LC_TELEPHONE="ru_RU.zzz"
LC_MEASUREMENT="ru_RU.zzz"
LC_IDENTIFICATION="ru_RU.zzz"
LC_ALL=


Но если подставить эти имена (как дефаулты) в определения локали программы, то возбудится исключение - нет такой локали:
Код:
bash-4.2$ ./randwr
terminate called after throwing an instance of 'std::runtime_error'
  what():  locale::facet::_S_create_c_locale name not valid
Аварийный останов (core dumped)


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 18 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB
[ Time : 0.100s | 19 Queries | GZIP : On ]