Hungry Mind , Blog about everything in IT - C#, Java, C++, .NET, Windows, WinAPI, ...

Tiesto in Kiev

Клёво было. Папка выдал "I just want to say: Kiev, you are the best. I will play for you all night". И играл 5 с половиной часов вместо заявленных 4-х. Садюга...

He is the boss of trance!
Not only the boss, he is the god of trance...
No... He is the boss of all gods of trance...

How to read unicode text file in C++

Не первый раз сталкиваюсь с задачей чтения UNICODE символов, строк из текстового файла стандартными средствами С++. И в очередной раз понимаю, как С++ устарел...

Первое решение, которое приходит в голову, - использовать классы std::wifstream и std::wstring. Но, к сожалению, результирующие строки заполнены мусором. Второй вариант - читать char-ы в режиме binary, после reinterpret_cast-ом получить wchar_t*. Но этот вариант очень неудобен, т.к. требует написания лишнего кода, нельзя пользоваться оператором >> и, как результат, istream_iterator.

Почему так? Во-первых, следует понять, что UNICODE - это не кодировка. Не совсем кодировка. UNICODE - это набор символов, а также способы их представления в 8-битной, 16-битной и 32-битной формах - кодировках UTF-8, UTF-16 и UTF-32 соответственно. Поэтому наш UNICODE-файл может содержать символы, закодированные одним из перечисленных способов.

Текущая версия стандарта насчитывает более миллиона символов. UTF-16 способен представить лишь 65536 из них. Тип wchar_t имеет разную длинну в зависимости от платформы (ОС, компилятора, ...). Для Windows - 2 байта, для Linux - 4 и т.д. В итоге мы пытаемся читать файл с неизвестной кодировкой в неизвестное представление строки символов из набора UNICODE. В результате - мусор.

Свою проблему я решил следующим способом:

  1. Сохранил текст в кодировке UTF-16.
  2. Вежливо попросил std::wifstream использовать специальный аспект (facet) для перекодирования символов.

    Стандартная библиотека содержит аспект std::codecvt. Компилятор, соответствующий стандарту, должен как минимум содержать специализацию std::codecvt<char, wchar_t, std::mbstate_t>, что позволяет читать ANSI символы в строку wchar_t. А нам нужно wchar_t в wchar_t. Для этого в библиотеке boost есть класс boost::archive::codecvt_null (#include <boost/archive/codecvt_null.hpp>).

Результирующий код:

std::wifstream &stream = ...;
std::locale loc(stream.getloc(), new boost::archive::codecvt_null<wchar_t>());
stream.imbue(loc);
std::vector<std:wstring> data(std::istream_iterator<std:wstring>(stream), std::istream_iterator<std:wstring>());

Кстати, есть еще utf8_codecvt_facet (#include <boost/detail/utf8_codecvt_facet.hpp>).

boost::random in a nutshell

Boost Random Number Library - библиотека для генерации случайных чисел. Условно поделена на 3 части:

  1. Генераторы.

    Генератор - это класс, который производит случайные числа. Некий алгоритм, который, как правило, имеет параметры. Качество генератора сильно зависит от этих параметров. Для каждого алгоритма есть специализация с правильно подобранными параметрами. Алгоритмы имеют различные требования к памяти, разное качество случайных чисел и, естественно, разную скорость.

  2. Распределения.

    Распределение - закон, который описывает область значений случайной величины и вероятности их принятия. Распределения есть дискретные, непрерывные. Чаще всего используются равномерные распределения - uniform distributions.

  3. Их комбинации - вариаторы.

    Вариатор совмещает геренатор и распределение.

Примеры.

Равномерное дискретное распределение.

boost::int32_t number;
boost::hellekalek1995 generator(GetTickCount());
number = generator();
boost::uniform_smallint<BYTE> distribution(1, 10);
BYTE result;
result = distribution(generator);
boost::variate_generator<boost::hellekalek1995, boost::uniform_smallint<BYTE>> random(generator, distribution);
result = random();

Кстати, генератору надо дать пинка - стартовое значение (seed). Я обычно использую GetTickCount.

Распределение Бернулли.

boost::int32_t number;
boost::hellekalek1995 generator(GetTickCount());
number = generator();
bool success;
boost::bernoulli_distribution<> distribution(0.2);
success = distribution(generator);
boost::variate_generator<boost::hellekalek1995, boost::bernoulli_distribution<>> random(generator, distribution);
success = random();
Copyright 2007-2011 Chabster