| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Ввод\вывод Unicode в C++ |
| Автор: shaukote 6.4.2013, 13:38 | ||||
| Всем доброго времени суток. Буду очень благодарен, если кто-нибудь здесь сможет мне помочь. Сначала кратко опишу ситуацию. Являясь студентом технического вуза, я постоянно пишу на C++ различные программы различной степени сложности, в основном - консольные. При этом я склонен работать с Unicode (wchar_t, L" ... ", std::wstring, std::wcin, std::wcout etc) и храню исходники в UTF-8, благо Sublime делает это по умолчанию. Чаще всего я работаю под Windows 7, соответственно компилирую свои поделия MinGW и запускаю их в cmd.exe. Однако иногда у меня возникает потребность сделать это в Linux, соответственно, с gcc и местной консолью. Соответственно, мне нужно как-то обеспечивать корректный ввод/вывод Unicode в своих программах. При чём желательно сделать это стандартными кроссплатформенными средствами. Теперь как я решал эту ситуацию. До этого момента я просто помещал в начало программы вызов
Однако с недавнего момента перестало. На протяжении последних дней я безуспешно пытался выяснить, в чем проблема, и в это время ввод/вывод то не работал, при этом ломаясь в самых странных местах. Прозвучит, глупо, возможно, но возникло ощущение, что оно зависит "от фазы Луны". Так что, судя по всему, этот метод не работает. Я решил посоветоваться со Страуструпом - он в своей книге рекомендует использовать класс std::locale. Что же, пробуем:
Во время выполнения получаем runtime_error, что говорит о том, что такой локали нету. :( Скажите пожалуйста, как корректно обеспечить ввод/вывод Unicode? |
| Автор: Alexeis 6.4.2013, 14:16 |
| В бусте есть затычка для ввода вывода юникода http://www.boost.org/doc/libs/1_33_1/libs/serialization/doc/codecvt.html |
| Автор: shaukote 6.4.2013, 14:20 |
| Но ведь и в STD есть (вроде бы как) средства для этого - те же wcin/wcout. Неужели нельзя обойтись без сторонних библиотек? |
| Автор: Alexeis 6.4.2013, 15:39 |
| wcin/wcout сами не умеют работать с кодировками. Они знают что такое 2х байтовый символ, но по умолчанию интерпретировать его будут через фасет codecvt . Как я понял, фасеты определяют преобразование из внутренней кодировки, которую использует программа во внешнюю которую используют потоки ввода/вывода. Вижу в С++11 ввели уже utf16 фасеты. Можно посмотреть тут. http://www.cplusplus.com/reference/codecvt/codecvt_utf16/ И еще проблема строчки locale russian("ru_RU.UTF-8"); состоит в том, что на нужной платформе может не оказаться фасета с таким именем в каталоге. Этот идентификатор "ru_RU.UTF-8" линуксового происхождения. |
| Автор: shaukote 6.4.2013, 18:19 |
| Эмм. А можно полюбопытствовать, как люди управляли кодировками ввода/вывода до появления C++11? Нежели исключительно платформозависимыми средствами?.. Просто задача-то вроде вполне стандартная, как-то же все это делают?.. |
| Автор: Alexeis 6.4.2013, 20:38 | ||
shaukote, в свое время я сам задавался этим вопросом. Гугл в основном выдает код типа
Или же 2й вариант для винды. Часто встречаются самописные варианты фасетов. Возможно стараются работать с файлами во внутренней кодировке или средствами языка С. Довольно неплохое описание нашел тут http://habrahabr.ru/post/107679/ Но автор использует самописные фасеты и рекомендует их для переносимости кода. Добавлено через 1 минуту и 10 секунд поскольку буст уже стал почти стандартом, я бы рекомендовал использовать бустовкие фасеты вместо самописных. |
| Автор: Alexeis 6.4.2013, 21:23 | ||
По отзывам в инете работает плохо. Лично я пользую _wfopen и гружу сразу в wstring так чтобы не было никаких конвертаций. Дальше перекодирую уже строки между собой платформозависимыми способами. Но вообще стараюсь работать только с wstring UTF16 без преобразований. Соответственно если файл в той же кодировке то можно хоть бинарно грузить. По крайней мере имею только конвертацию строк. Файлы работают одинаково. |
| Автор: shaukote 7.4.2013, 00:50 | ||||
Вы это серьёзно? Если да, то можете поподробнее разъяснить почему так?
Печально, конечно же. Хорошо, позвольте слегка переформулировать вопрос. Как лучше всего устанавливать кодировку в ввода/вывода в отдельных системах (Windows\Linux). Т.е., в Linux, наверное, вполне хорошим решением будет и
А как лучше всего в Windows это делать (начхав на платформонезависимость)? Добавлено через 2 минуты и 39 секунд И да, Alexeis, спасибо за ссылки. (: |
| Автор: volatile 7.4.2013, 01:31 | ||||
Здесь уже был когда-то большой срач диспут по поводу использования UTF-8. мое имхо (но есть и другие мнения), что UTF-8 не предназначена для активной работы со строками. Эта кодировка для передачи данных по сетям, может быть для хранения, но никак не для активной работы.
Я строронник этого способа. (хотя у него и есть недостатки). Но у других способов недостатков еще больше. http://forum.vingrad.ru/forum/topic-335725/kw-wcout-locale-%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0.html |
| Автор: shaukote 7.4.2013, 17:32 | ||
Не работает с MSVC++ ни в VS, ни в Qt Creator. Английские буквы выводятся вопросительными знаками, на вводе русских вообще подвисает. :( |
| Автор: shaukote 7.4.2013, 18:07 | ||
В MinGW вообще не компилируется. :(
|
| Автор: Alexeis 7.4.2013, 20:43 | ||
Странно сейчас проверил на С++ Builder так работает правильно пример безо всяких фасетов
Чего только не делал и TCHAR менял тип и кодировку исходника, работает как часы. Жаль нет под рукой других компиляторов. Помниться у меня проблема была именно с файлами. |
| Автор: volatile 7.4.2013, 23:37 |
shaukote, да там консольный ввод не работает. это и есть недостаток, но его можно обойти. (лично у меня не было задач, где нужно было вводить с консоли, поэтому пока меня это устраивает.) Все остальное работает. С файловым вводом вообще проблем никогда не было. Добавлено через 2 минуты и 43 секунды более того, в винде кроме вышеназванной фичи вообще больше нет средств для вывода мультиязычного текста в консоль.) насколько я знаю. |
| Автор: shaukote 8.4.2013, 01:54 | ||||
| Alexeis, я в шоке, но первая половина и у меня работает. А вот на строковом потоке уже начинается бардак - на некоторых буквах он работает некорректно. volatile, по приведённой Вами ссылке Вы пишете:
Я же точно так же сделал, почему же у меня ввод не работает?
А странно-полуработающий вариант Alexeis? |
| Автор: bsa 8.4.2013, 11:36 |
| http://forum.vingrad.ru/index.php?show_type=forum&showtopic=269794&st=0&anchor=entry2086699 |
| Автор: volatile 8.4.2013, 20:17 |
имеется ввиду именно мультиязычный текст. не только русский. Юникод собственно для того и существует, чтобы выводить мультиязычный текст. Если вам нужен только русский, то да, можете выбирать варианты. |
| Автор: shaukote 8.4.2013, 21:52 | ||
Насколько я понял, там речь идёт несколько о другом.
Простите, но я вообще не понял, к чему Вы это сказали. Мне не дают покоя два вопроса: 1) Почему не работает Ваш вариант с _setmode? Хотя вроде как должен корректно работать и на ввод и на вывод. 2) Как вообще может работать вариант Alexeis? Буду крайне признателен, если Вы сможете мне их разъяснить. |
| Автор: volatile 8.4.2013, 23:38 | ||||||
Нет на ввод он действительно в этом виде не работает . (именно на ручной ввод с консоли) объясню почему меня это устраивает: я никгда не делаю приложений с ручным вводом с консоли. Если нужен диалог с пользователем, то имхо, нужно делать GUI! Удел консольных приложений работа с ком.строкой, перенаправленный ввод, вывод. и т.д. Вобщем если вам нужен ручной консольный ввод, то вам это не подойдет. Сорри что побеспокоил.
В студии этот код работает только в неконсольном приложении, и фактически выводит в кодировке cp866 перенаправьте в файл, увидите. (никакой мультиязычности т.е. нет) В нормальном юникодном приложении этот код выдает следующее:
Да, и кстати , вариант с _setmode нужно тоже проверять на настоящем юникодном приложении.. |
| Автор: shaukote 8.4.2013, 23:42 | ||
А Вы вроде бы говорили, что можно это как-то "обойти"?..
"Настоящем юникодном приложении"?.. Что Вы под этим подразумеваете? |
| Автор: Alexeis 8.4.2013, 23:52 | ||
Подтверждаю, сегодня проверял на VS2005 . Файловый ввод/вывод UTF8 заработал только через бустовские локали, а вот UTF16 никак. Единственный рабочий способ через стандартные фасеты С++11 . Делают шаблонный фасет из wchar_t в wchar_t причем там по ходу реальное преобразование, поскольку юникодные потоки выгребают файл в буфер из char, точно также как это делают не юникодные. И если для UTF8 еще оправдана сборка символов с char-в, то для wchar_t сие преобразование выглядит как бред. Возможно, местные гуру С++ найдут в этом сакральный смысл, но мое ИМХО, что нехай ifstream рассматривает файл как char-ы и учиться извлекать из него строк как string так и wstring, а вот wifstream должен файл рассматривать как поток wchar_t и уже их транслировать во что угодно. P.S. удивительно как в билдере консолька юникодная. Вероятно, имеет место тотальная юникодизация видимо разработчики где-то удачно накосячили раз работает. |