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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> C++ и Unicode 
:(
    Опции темы
Ulysses4j
Дата 7.7.2008, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



Извините, что дублирую тему, которая сейчас обсуждается рядом, но как-то она меня не радует, и толькаться не хотелось бы. Дело в том, что волнуют меня близкие вещи к тому, что обсуждается там, но то обсуждение на мой взгляд как-то малоконструктивно, потому я решил задать максимально конкретный, четкий, простой вопрос.

Может кто-нибудь привести работающий пример чтения и вывода на консоль файла в UTF-8 (или любой другой Unicode-кодировки). Вот, что написал я:
Код
#include <fstream>
#include <iostream>
#include <string>

using namespace std;

int main() {
    wifstream f("test.txt");
    if (!f.is_open())
        throw 42;
    wstring s;
    getline(f, s);
    wcout << s << endl;
}

Выводит пустую строку. Содержимое файла test.txt в UTF-8, это одна строка в кириллице.


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
JackYF
Дата 7.7.2008, 20:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

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



Интересно. На деле с Unicode я работал только средствами Qt, а этот код у меня тоже выводит пустую строку.
Более того, код "f >> s;" вообще генерирует

Цитата

terminate called after throwing an instance of 'std::ios_base::failure'
  what():  basic_filebuf::underflow invalid byte sequence in file


Возможно, оно хочет BOM в начале файла. Не знаю...


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Annihilator
Дата 7.7.2008, 21:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


bytegrinder
**


Профиль
Группа: Участник
Сообщений: 493
Регистрация: 21.11.2006
Где: Омск

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



может это поможет


--------------------
Если вы не можете сделать хоpошyю пpогpаммy, сделайте, чтобы она по кpайней меpе выглядела хоpошо
PM ICQ   Вверх
Ulysses4j
Дата 7.7.2008, 21:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



JackYF, скажу насчет Qt: я искал в сети ответ на свой вопрос, разумеется. Так вот все Unicode-решения на C++ были завязаны на некую библиотеку. Boost предлагает пользоваться поделием от IBM, есть варианты с MFC, ну и Qt, да. Это очень печально, если никак нельзя получить из коробки поддержку таких простейших операций, как ввод-вывод. Стандарт C++ устаревает все сильней.

Annihilator, не устраивает по двум параметрам: 
1. C — не люблю этот язык программирования.
2. Привязка к вендору (gcc, glibc).
Забавно, что даже учитывая то, что ISO C99 попытался как-то осмысленно подойти к поддержке Unicode, некоторые стандартные строковые функции C остаются неприсобленными к нему.

Однако, спасибо за отклик.


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
bsa
Дата 7.7.2008, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Ulysses4j, функция mbstowcs соответствует стандарту C99 и не зависит от библиотек и платформ. Другое дело, что далеко не все производители поддержали этот стандарт.
PM   Вверх
Ulysses4j
Дата 8.7.2008, 00:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



bsa, она даже соответствует ISO/IEC 9899:1990, но дело в том, что, как я уже говорил, в первую очередь меня не устраивает то, что это C. Я и тему соответствующим образом назвал. Это мне придется, чтобы использовать mb*, открывать файл как FILE*, потом fread какие-нибудь, это по определенным причинам в данном случае недопустимо. Мне хотелось бы решения на C++.

Это сообщение отредактировал(а) Ulysses4j - 8.7.2008, 01:36


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
Ulysses4j
Дата 8.7.2008, 01:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



Собственно, в стандарте C++ сказано, что mbstowcs с сотоварищи включены. И хотя мне нельзя завязываться на C-интерфейсы, я решил в качестве эксперимента попробовать:
Код
#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

int main() {
    char cs[] = "Здравствуй, мир";
    const size_t len = 32; // с запасом
    wchar_t wcs[len];
    mbstowcs(wcs, cs, len);
    wstring s(wcs);
    wcout << s << endl;
}

Текст программы в UTF-8, соответственно, там же должны быть литералы. Выводятся кракозябры. 

Я так понимаю, нужно еще иметь представление о локалях. Я с ними плохо дружу. Системная у меня ru_RU.UTF-8 (в частности, это содержимое переменной окружения LANG).


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
Torsten
Дата 8.7.2008, 20:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Ulysses4j
Цитата
JackYF, скажу насчет Qt: я искал в сети ответ на свой вопрос, разумеется. Так вот все Unicode-решения на C++ были завязаны на некую библиотеку. Boost предлагает пользоваться поделием от IBM, есть варианты с MFC, ну и Qt, да. Это очень печально, если никак нельзя получить из коробки поддержку таких простейших операций, как ввод-вывод. Стандарт C++ устаревает все сильней.


Причем тут стандарт ?
Какая у тебя кодировка в консоли (или куда ты там выводишь) установлена он в той и выводит. В linux все просто. Установи нужную кодировку через контекстное меню (для konsole) и все выведет нормально. Правда исходник нужно поправить, чтобы было нормальный std::string и std::ifstream - тогда все будет нормально.

Написать классы для поддержки utf-8, utf-16 и русских кодировок совсем не сложно.

Это сообщение отредактировал(а) Torsten - 8.7.2008, 20:54
--------------------
We have no begining, we have no end. We are infinite.
PM MAIL   Вверх
Ulysses4j
Дата 8.7.2008, 21:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



Цитата(Torsten @  8.7.2008,  20:51 Найти цитируемый пост)
Причем тут стандарт ?

При том, что в современных языках, где поддержка Unicode реализована изначально и осмысленно, никаких вопросов не возникает. С этими wchar_t какая-то байда, потому что когда писался Стандарт 98, люди, по всей видимости, во-первых, не воспринимали Unicode достаточно серьезно (не сказать: не понимали достаточно глубоко), во-вторых, у них как обычно, не было времени над этим подумать. Если откроешь страницу TR2, то увидишь, что в первых рядах «желаемых предложений» стоит поддержка Unicode.


Цитата(Torsten @  8.7.2008,  20:51 Найти цитируемый пост)
Какая у тебя кодировка в консоли (или куда ты там выводишь) установлена он в той и выводит.

Да что ты говоришь, а я-то думал, что он случайным образом кодировку выбирает. У меня GNU/Linux с локалью ru_RU.UTF-8, в консоли (никакая не Konsole, естественно, потому что не KDE), ясное дело, UTF-8.

Цитата(Torsten @  8.7.2008,  20:51 Найти цитируемый пост)
Написать классы для поддержки utf-8, utf-16 и русских кодировок совсем не сложно.

Не надо меня лечить: или выложи свою реализацию, или скажи почему приведенный мной код не работает.

Это сообщение отредактировал(а) Ulysses4j - 8.7.2008, 21:22


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
bsa
Дата 8.7.2008, 22:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Ulysses4j, попробуй добавить setlocale(LC_CTYPE, "") первой строчкой в main()
PM   Вверх
Ulysses4j
Дата 8.7.2008, 22:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



Спасибо, bsa, заработало. Получается, возвращаясь к первоначальной задаче: прочитать файл в UTF-8 — нужно читать файл в char[] а потом конвертить в wchar_t, а потом уже загонять в wstring. Как-то не по человечески это.


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
Ulysses4j
Дата 9.7.2008, 02:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



Если кому-то интересно, вот что еще удалось разузнать.

wstring можно инициализировать литералами (если исходник в Unicode) вот так:
Код
wstring ws(L"Здравствуй, мир"); // L это не опечатка, а знак того, что литерал надо понимать как wchar_t[]

Далее про чтение файлов. Все сильно зависит от того, какие локали установлены в операционной системе. В никсах можно посмотреть locale -a а в Windows через Панель управления, Региональные и языковые настройки (или как-то так). У меня в никсах есть упоминания только про UTF-8, так что пока я вроде бы научился читать и писать файлы в UTF-8 (соответственно, в UTF-16 не получается):
Код
#include <iostream>
#include <fstream>
#include <locale>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace std;

int main() {
    locale::global(locale(""));
    wifstream f("test.txt"); // содержит "Привет"
    wofstream out("out.txt");
    if (! f.is_open())
        throw 42;
    wstring s1;
    getline(f, s1);
    out << "input: " << s1 << endl <<
      "to_upper: " <<  boost::algorithm::to_upper_copy(s1) << endl;
    out << L"Здравствуй, мир" << endl;
}

После этого out.txt содержит:
Код
input: Привет
to_upper: ПРИВЕТ
Здравствуй, мир


Строка locale::global(locale("")); была изначально навеяна советом bsa, за что ему еще раз отдельное спасибо и плюс в карму по возможности (если у кого из окружающих есть полномочия). Медитация со стандартом в одной руке и Гуглом в другой привела к следующим фактам:  вначале каждой программы, неявно выставляется локаль с особым именем "C", которая существует как бы в любой системе и содержит минимальные сведения для того, чтобы программа на C/C++ могла работать. Этот минимум  может совсем не устравать. Первое, что можно сделать это явно попросить взять стандартную системную локаль: как раз вызвав setlocale(LC_ALL, "") (LC_TYPE, как советовал bsa, может хватить для действий со строками, да) и/или locale::global(locale(""));, в зависимости от того, какими средствами собираетесь пользоваться (пустая строка в обоих случаях означает, что настоящее имя системной локали знает система, это как бы конструктор по умолчанию).

Ну вот, а что может быть лучше я и не знаю. В принципе, приведенную выше программу можно назвать переносимой в следующем смысле: она будет корректно работать, если файл test.txt находится в кодировке, соответствующей системной локали. Для последних Windows это часто UTF-16. Для интернационализированных никсов это часто UTF-8. Меня сильно волнуют вопросы переносимости, так что если кто-то поиграется с этим под виндами или просто сможет высказать какие-то ценные мысли в этом русле, буду признателен.

Такие дела. Всем спасибо за участие.

Это сообщение отредактировал(а) Ulysses4j - 9.7.2008, 02:04


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
JackYF
Дата 9.7.2008, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

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



Цитата(Ulysses4j @  9.7.2008,  01:02 Найти цитируемый пост)
за что ему еще раз отдельное спасибо и плюс в карму по возможности (если у кого из окружающих есть полномочия).

У тебя есть 100 постов, подними ему репутацию.



--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Ulysses4j
Дата 9.7.2008, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 304
Регистрация: 6.6.2007
Где: Ростов-на-Дону

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



Под Windows не получается выставить локаль, которая бы распознавала UTF-*, не знаю, какое у нее должно быть имя, пробовал разные варианты, гуглил — все попусту. У системной: «Russian_Russia.CP1251», соответственно, понимает только однобайтовую cp1251.


--------------------
Communication is critical to the job of a programmer.
C. Jazdzewski. Fatherly Advice To New Programmers
PM MAIL WWW   Вверх
NovorosSupport
Дата 21.7.2009, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата

не знаю, какое у нее должно быть имя, пробовал разные варианты, гуглил — все попусту


Инструкция
setlocale(LC_ALL,"Russian");
возвращает в моём и, очевидно, в твоём случае "Russian_Russia.1251" smile

Хотя мне проще запомнить и использовать
setlocale(LC_ALL, ".1251" );

Цитата

Получается, возвращаясь к первоначальной задаче: прочитать файл в UTF-8 — нужно читать файл в char[] а потом конвертить в wchar_t, а потом уже загонять в wstring. Как-то не по человечески это


После указания конкретной кодовой страницы инструкцией setlocale(LC_ALL, ".1251" ) ничего этого уже не понадобилось. Файл с кириллицей корректно считывался в объект string и затем корректно выводился в cout! Причем в моём случае даже wcout стал не нужным.

подробнее о команде и её параметрах можно почитать здесь
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

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

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

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

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


 




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


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

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