Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ввод\вывод Unicode в C++ 
:(
    Опции темы
shaukote
Дата 6.4.2013, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



Всем доброго времени суток.

Буду очень благодарен, если кто-нибудь здесь сможет мне помочь.

Сначала кратко опишу ситуацию. 
Являясь студентом технического вуза, я постоянно пишу на C++ различные программы различной степени сложности, в основном - консольные. При этом я склонен работать с Unicode (wchar_t, L" ... ", std::wstring, std::wcin, std::wcout etc) и храню исходники в UTF-8, благо Sublime делает это по умолчанию.
Чаще всего я работаю под Windows 7, соответственно компилирую свои поделия MinGW и запускаю их в cmd.exe.
Однако иногда у меня возникает потребность сделать это в Linux, соответственно, с gcc и местной консолью.
Соответственно, мне нужно как-то обеспечивать корректный ввод/вывод Unicode в своих программах. При чём желательно сделать это стандартными кроссплатформенными средствами.

Теперь как я решал эту ситуацию.  
До этого момента я просто помещал в начало программы вызов 
Код
setlocale(LC_ALL, "");
 и всё как-то работало.
Однако с недавнего момента перестало. 
На протяжении последних дней я безуспешно пытался выяснить, в чем проблема, и в это время ввод/вывод то не работал, при этом ломаясь в самых странных местах.
Прозвучит, глупо, возможно, но возникло ощущение, что оно зависит "от фазы Луны".
Так что, судя по всему, этот метод не работает.

Я решил посоветоваться со Страуструпом - он в своей книге рекомендует использовать класс std::locale. Что же, пробуем:
Код

#include <locale>
#include <iostream>
#include <string>
#include <sstream>

using std::locale;
using std::wcin;
using std::wcout;
using std::endl;
using std::wstring;
using std::wistringstream;

int main(int argc, char const *argv[])
{
    locale russian("ru_RU.UTF-8");
    wcin.imbue(russian);
    wcout.imbue(russian);
    
    wstring text, word;
    getline(wcin, text);
    wcout << text << endl;
     
    wistringstream input(text);

    while (input >> word)
        wcout << word << endl;


    return 0;
}

Во время выполнения получаем runtime_error, что говорит о том, что такой локали нету. :(

Скажите пожалуйста, как корректно обеспечить ввод/вывод Unicode?
PM MAIL   Вверх
Alexeis
Дата 6.4.2013, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



В бусте есть затычка для ввода вывода юникода http://www.boost.org/doc/libs/1_33_1/libs/...oc/codecvt.html


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
shaukote
Дата 6.4.2013, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



Но ведь и в STD есть (вроде бы как) средства для этого - те же wcin/wcout. Неужели нельзя обойтись без сторонних библиотек?
PM MAIL   Вверх
Alexeis
Дата 6.4.2013, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



wcin/wcout сами не умеют работать с кодировками. Они знают что такое 2х байтовый символ, но по умолчанию интерпретировать его будут через фасет codecvt . Как я понял, фасеты определяют преобразование из внутренней кодировки, которую использует программа во внешнюю которую используют потоки ввода/вывода. Вижу в С++11 ввели уже utf16 фасеты. Можно посмотреть тут.
http://www.cplusplus.com/reference/codecvt/codecvt_utf16/

И еще проблема строчки locale russian("ru_RU.UTF-8"); состоит в том, что на нужной платформе может не оказаться фасета с таким именем в каталоге. Этот идентификатор "ru_RU.UTF-8" линуксового происхождения.  

Это сообщение отредактировал(а) Alexeis - 6.4.2013, 16:09


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
shaukote
Дата 6.4.2013, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



Эмм.
А можно полюбопытствовать, как люди управляли кодировками ввода/вывода до появления C++11?
Нежели исключительно платформозависимыми средствами?..

Просто задача-то вроде вполне стандартная, как-то же все это делают?..
PM MAIL   Вверх
Alexeis
Дата 6.4.2013, 20:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



shaukote, в свое время я сам задавался этим вопросом. Гугл в основном выдает код типа
Цитата

locale russian("ru_RU.UTF-8"); 

Или же 2й вариант для винды. 

Часто встречаются самописные варианты фасетов. Возможно стараются работать с файлами во внутренней кодировке или средствами языка С.

Довольно неплохое описание нашел тут http://habrahabr.ru/post/107679/
Но автор использует самописные фасеты и рекомендует их для переносимости кода.

Добавлено через 1 минуту и 10 секунд
поскольку буст уже стал почти стандартом, я бы рекомендовал использовать бустовкие фасеты вместо самописных. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
volatile
Дата 6.4.2013, 21:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(shaukote @  6.4.2013,  18:19 Найти цитируемый пост)
А можно полюбопытствовать, как люди управляли кодировками ввода/вывода до появления C++11?
Нежели исключительно платформозависимыми средствами?..

имхо, да.

не уверен даже, что в C++11 сделали наконец это на 100%, (не изучал пока этот вопрос)
но до этого, ничем платформонезависимым в юникодных кодировках и не пахло.

shaukote
Цитата(shaukote @  6.4.2013,  13:38 Найти цитируемый пост)
 я безуспешно пытался выяснить, в чем проблема, и в это время ввод/вывод то не работал, при этом ломаясь в самых странных местах

Цитата(shaukote @  6.4.2013,  13:38 Найти цитируемый пост)
locale russian("ru_RU.UTF-8");


а что вы хотите с UTF-8 под другому и не бывает.  smile 


PM MAIL   Вверх
Alexeis
Дата 6.4.2013, 21:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Цитата(volatile @  6.4.2013,  22:03 Найти цитируемый пост)
не уверен даже, что в C++11 сделали наконец это на 100%, (не изучал пока этот вопрос)

  По отзывам в инете работает плохо. Лично я пользую _wfopen и гружу сразу в wstring так чтобы не было никаких конвертаций. Дальше перекодирую уже строки между собой платформозависимыми способами. Но вообще стараюсь работать только с wstring UTF16 без преобразований. Соответственно если файл в той же кодировке то можно хоть бинарно грузить. 
По крайней мере имею только конвертацию строк. Файлы работают одинаково. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
shaukote
Дата 7.4.2013, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



Цитата(volatile @  6.4.2013,  21:03 Найти цитируемый пост)
а что вы хотите с UTF-8 под другому и не бывает.  

Вы это серьёзно? Если да, то можете поподробнее разъяснить почему так?


Цитата(volatile @  6.4.2013,  21:03 Найти цитируемый пост)
не уверен даже, что в C++11 сделали наконец это на 100%, (не изучал пока этот вопрос)
но до этого, ничем платформонезависимым в юникодных кодировках и не пахло.

Цитата(Alexeis @  6.4.2013,  21:23 Найти цитируемый пост)
 По отзывам в инете работает плохо

Печально, конечно же.

Хорошо, позвольте слегка переформулировать вопрос.
Как лучше всего устанавливать кодировку в ввода/вывода в отдельных системах (Windows\Linux).
Т.е., в Linux, наверное, вполне хорошим решением будет и 
Код

locale russian("ru_RU.UTF-8");
wcin.imbue(russian);
wcout.imbue(russian);

А как лучше всего в Windows это делать (начхав на платформонезависимость)?

Добавлено через 2 минуты и 39 секунд
И да, Alexeis, спасибо за ссылки. (: 

Это сообщение отредактировал(а) shaukote - 7.4.2013, 00:52
PM MAIL   Вверх
volatile
Дата 7.4.2013, 01:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(shaukote @  7.4.2013,  00:50 Найти цитируемый пост)
Вы это серьёзно? Если да, то можете поподробнее разъяснить почему так?

Здесь уже был когда-то большой срач диспут по поводу использования UTF-8.
мое имхо (но есть и другие мнения), что UTF-8 не предназначена для активной работы со строками. Эта кодировка для передачи данных по сетям, может быть для хранения, но никак не для активной работы.

Цитата(shaukote @  7.4.2013,  00:50 Найти цитируемый пост)
А как лучше всего в Windows это делать (начхав на платформонезависимость)?

Я строронник этого способа. (хотя у него и есть недостатки). Но у других способов недостатков еще больше.
вот почитайте отсюда
PM MAIL   Вверх
shaukote
Дата 7.4.2013, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



Код

#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <string>

using namespace std;

int main()
{
    _setmode(_fileno(stdout), _O_WTEXT);
    _setmode(_fileno(stdin), _O_WTEXT);

    wstring str;
    getline(wcin, str);
    wcout << str << endl;

    return 0;
}

Не работает с MSVC++ ни в VS, ни в Qt Creator.
Английские буквы выводятся вопросительными знаками, на вводе русских вообще подвисает. :(
PM MAIL   Вверх
shaukote
Дата 7.4.2013, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



В MinGW вообще не компилируется. :(
Код

C:\Users\shau-kote\YandexDisk>g++ test.cpp
test.cpp: В функции <int main()>:
test.cpp:11:22: ошибка: нет декларации <stdout> в этой области видимости
test.cpp:11:28: ошибка: нет декларации <_fileno> в этой области видимости
test.cpp:11:31: ошибка: нет декларации <_O_WTEXT> в этой области видимости
test.cpp:12:22: ошибка: нет декларации <stdin> в этой области видимости

PM MAIL   Вверх
Alexeis
Дата 7.4.2013, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Странно сейчас проверил на С++ Builder так работает правильно пример безо всяких фасетов
Код

    wstring text, word;
    getline(wcin, text);
    wcout << text << endl;

    wistringstream input(text);
    while (input >> word)
        wcout << word << endl;

Чего только не делал и TCHAR менял тип и кодировку исходника, работает как часы. Жаль нет под рукой других компиляторов. Помниться у меня проблема была именно с файлами. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
volatile
Дата 7.4.2013, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(shaukote @  7.4.2013,  17:32 Найти цитируемый пост)
getline(wcin, str);

shaukote, да там консольный ввод не работает. это и есть недостаток, но его можно обойти.
(лично у меня не было задач, где нужно было вводить с консоли, поэтому пока меня это устраивает.)
Все остальное работает.
С файловым вводом вообще проблем никогда не было.

Добавлено через 2 минуты и 43 секунды
более того, в винде кроме вышеназванной фичи вообще больше нет средств для вывода мультиязычного текста в консоль.)
насколько я знаю.
PM MAIL   Вверх
shaukote
Дата 8.4.2013, 01:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 13.2.2013

Репутация: нет
Всего: нет



Alexeis, я в шоке, но первая половина и у меня работает. А вот на строковом потоке уже начинается бардак - на некоторых буквах он работает некорректно.


volatile, по приведённой Вами ссылке Вы пишете:
Цитата

Но есть очень простое, но увы, нестандартное решение
100% в винде рашает только недокументированная инструкция
_setmode( _fileno( stdout ), _O_WTEXT ); 
если еще и ввод нужен мультиязыковый, то еще и
_setmode( _fileno( stdin ), _O_WTEXT ); 

Это решает абсолютно все проблемы с юникодом в  вин консоли.

Я же точно так же сделал, почему же у меня ввод не работает?

Цитата(volatile @  7.4.2013,  23:37 Найти цитируемый пост)
более того, в винде кроме вышеназванной фичи вообще больше нет средств для вывода мультиязычного текста в консоль.)
насколько я знаю. 

А странно-полуработающий вариант Alexeis?  smile 

Это сообщение отредактировал(а) shaukote - 8.4.2013, 01:55
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0963 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.