Re: Русские строки
От: VoidEx  
Дата: 16.11.08 18:55
Оценка: 4 (2)
Здравствуйте, Аноним, Вы писали:

А>Собственно как можно сделать так что бы в string a хранились символы в кириллицы а не ироглифами.

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

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

std::string narrow(std::wstring const & wstr, std::locale const & loc, char def = '?')
{
    if (wstr.empty())
        return std::string();

    std::string ret;
    ret.resize(wstr.length());

    std::use_facet<std::ctype<wchar_t> >(loc).narrow(&wstr[0], &wstr[0] + wstr.length(), '?', &ret[0]);

    return ret;
}

std::wstring widen(std::string const & str, std::locale const & loc)
{
    if (str.empty())
        return std::wstring();

    std::wstring ret;
    ret.resize(str.length());

    std::use_facet<std::ctype<wchar_t> >(loc).widen(&str[0], &str[0] + str.length(), &ret[0]);

    return ret;
}

std::string to1251(std::string const & cp866)
{
    std::string ret;
    ret.reserve(cp866.length());

    for (std::size_t i = 0, e = cp866.length(); i < e; ++i)
    {
        wchar_t wide = std::use_facet<std::ctype<wchar_t> >(std::locale(".866")).widen(cp866[i]);
        ret.push_back(std::use_facet<std::ctype<wchar_t> >(std::locale(".1251")).narrow(wide, '?'));
    }

    return ret;
}

int main(int argc, char* argv[])
try
{
    std::string cp866;
    std::cin >> cp866; // Кодировка в консоли — CP866
    std::string cp1251 = to1251(cp866); // Преобразуем в CP1251

    std::locale::global(std::locale("")); // Устанавливаем текущую локаль (русскую)
    // можно также russian_russia, russian_russia.866, russian_russian.1251, .866, .1251
    // В данном случае установлена .1251 == russian_russia.1251

    std::cin.imbue(std::locale(".866")); // Почему-то влияния не имеет. Если напишу .1251, ничего не изменится
    std::cout.imbue(std::locale()); // На вывод ставим текущую локаль
    std::wcin.imbue(std::locale(".866")); // А здесь всё ок
    std::wcout.imbue(std::locale()); // Аналогично

    std::cout << cp1251 << std::endl; // Выводим строку в CP1251. Будут крокозябры, если текущая локаль не .1251
    std::cin >> cp1251; // Читается всё равно в CP866
    std::cout << cp1251 << std::endl; // Соот-но тут будут крокозябры, если текущая локаль не .866

    std::wstring wtest;
    
    std::wcin >> wtest;
    std::wcout << wtest << std::endl;

    std::string test;

    std::wcin >> wtest;
    test = narrow(wtest, std::locale(".1251")); // Преобразуем в CP1251
    wtest = widen(test, std::locale(".1251")); // Обратно, неясно только куда обратно? Видимо, в глобальную локаль,
    // ибо последующий вывод срабатывает как при .866, так и при .1251
    std::cout << test; // Будут крокозябры, если локаль не .1251
    std::wcout << wtest << std::endl;

    return 0;
}
catch (std::exception const & e) // Конструкторы std::locale кидают исключения на неверное имя
{
    std::cerr << e.what() << std::endl;
    return -1;
}


Неясно только, почему локали .866 .1251 не имеют действия на ctype<char> и std::cin/cout.
Т.е. если в функции to1251 поменять wchar_t на char, то работать не будет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.