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. В результате - мусор.
Свою проблему я решил следующим способом:
- Сохранил текст в кодировке UTF-16.
- Вежливо попросил
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>).
4 коммент.:
У меня нет проблем чтения Unicode файлов. ArchLinux, GCC 4.4.2. Вот пример чтения построчно файла.
// Start file "Unicode.cpp"
#include < iostream >
#include < fstream >
#include < string >
#include < vector >
using namespace std;
int main()
{
vector< string > v;
ifstream in("Unicode.cpp");
string line;
// Читаем файл построчно
while(getline(in, line))
v.push_back(line);
// Выводим из вектора по
// строке с добавлением номеров строк
for(int i=v.size(); i != 0; i--)
cout << i << ": " << v[i-1] << endl;
return(0);
}
Проблем не было только из-за того, что в файле был записан текст в UTF-8 и кодировка консоли - UTF-8.
Отправить комментарий