Как преобразовать строку std::u32string в нижний регистр?

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Сохранив оригинал строки.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Если оригинал нужно сохранить, то придётся предварительно откопировать строку.

Для преобразования в нижний регистр можно воспользоваться функцией tolower из пространства имён std, применив её к каждому символу строки. В С++ (в отличии от С), есть перегруженный вариант этой функции, принимающий в качестве дополнительного параметра локаль (locale). Он-то нам и нужен. Само собой, локаль должна быть Russian, если хочешь, чтобы понижение регистра работало и для русских символов.

Небольшая заметка, касающаяся конкретно MinGW. В 32-битной версии нет стандартной русской локали. Мне пришлось руками написать фасет (facet) ctype, и проставить его в стандартную сишную локаль, чтобы алгоритм заработал для русских символов. Судя по форумам, знающие люди пишут, что в 64-битной версии компилятора этот недочёт устранён. Я ещё это не проверял, но так как у тебя именно такой компилятор, то можешь попробовать и рассказать нам получилось ли.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Romeo писал(а):если хочешь, чтобы понижение регистра работало и для русских символов.
Как раз только их преобразование и обязательно.
Romeo писал(а):принимающий в качестве дополнительного параметра локаль (locale). Он-то нам и нужен. Само собой, локаль должна быть Russian
Говорит, что
'Russian' was not declared in this scope|
.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Покажи, как локаль создал. Такое ощущение, что Russian ты пытаешься использовать, как идентификатор.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Romeo писал(а):Покажи, как локаль создал. Такое ощущение, что Russian ты пытаешься использовать, как идентификатор.
Ну да. А как надо?
Romeo писал(а):Мне пришлось руками написать фасет (facet) ctype, и проставить его в стандартную сишную локаль
Что это такое и как его писать?
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Сионист писал(а):Ну да. А как надо?
Судя по форумам, на MinGW 64 должно работать вот так:

Код: Выделить всё

std::wstring ws(L"some Русский текст");
std::locale loc("Russian");
std::transform(ws.begin(), ws.end(), ws.begin(), std::bind2nd(std: :p tr_fun(&std::tolower<wchar_t>), loc));
Так же есть люди, которые говорят, что вместо "Russian" нужно/можно писать "ru_RU.UTF-8".

Но мне на практике проверить не удалось, так как MinGW 32, которым я пользуюсь, не поддерживает русскую кодировку (кидает исключение в конструкторе std::locale, если передать что-то, кроме пустой строки). Мне пришлось пойти окольными путями.
Сионист писал(а):Что это такое и как его писать?
Как написать фасет расскажу, если попробуешь со стандартной локалью, и у тебя ничего не получится. А вообще, этот вопрос гуглится с полпинка. Начинать нужно с конструктора locale, который принимает оригинальную локаль и facet.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Аварийное завершение с зелёным прогрессбаром.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Ты c "ru_RU.UTF-8" тоже пробовал запускать?

А если в try взять и сделать catch(...), тогда что?

Подозреваю, что летит эксепшн из конструктора std::locale. И, если так, то тогда врут на форуме, что на MinGW 64 всё исправлено. Тогда нужно свой фасет делать. Можешь мой взять (см. следующие 2 сообщения, по лимиту символов не влазит в это).

Проставляется этот фасет в локаль вот таким образом:

Код: Выделить всё

russian_ctype rct;
std::locale loc(std::locale(), &rct);
Будь осторожней, если собираешься возвращаться локаль из функции или делать её статической. Дело в том, что она не владеет фасетами, а лишь содержит поинтеры на них (так стандартом положено). Так что если локаль будешь делать статической, чтобы использовать во всём проекте одну, то фасет тоже статическим делай.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Код: Выделить всё

      class russian_ctype : public std::ctype<wchar_t>
      {
         using _base = std::ctype<wchar_t>;
      
      public:
         russian_ctype() = default;

      protected:
         virtual wchar_t do_toupper(wchar_t __c) const override
         {
            using toupper_vec_base = std::vector<std: :p air<wchar_t, wchar_t>>;
      
            static class toupper_vec : public toupper_vec_base
            {
            public:
               toupper_vec() : toupper_vec_base()
               {
                  reserve(33);
                  push_back(std::make_pair(L'а', L'А'));
                  push_back(std::make_pair(L'б', L'Б'));
                  push_back(std::make_pair(L'в', L'В'));
                  push_back(std::make_pair(L'г', L'Г'));
                  push_back(std::make_pair(L'д', L'Д'));
                  push_back(std::make_pair(L'е', L'Е'));
                  push_back(std::make_pair(L'ё', L'Ё'));
                  push_back(std::make_pair(L'ж', L'Ж'));
                  push_back(std::make_pair(L'з', L'З'));
                  push_back(std::make_pair(L'и', L'И'));
                  push_back(std::make_pair(L'й', L'Й'));
                  push_back(std::make_pair(L'к', L'К'));
                  push_back(std::make_pair(L'л', L'Л'));
                  push_back(std::make_pair(L'м', L'М'));
                  push_back(std::make_pair(L'н', L'Н'));
                  push_back(std::make_pair(L'о', L'О'));
                  push_back(std::make_pair(L'п', L'П'));
                  push_back(std::make_pair(L'р', L'Р'));
                  push_back(std::make_pair(L'с', L'С'));
                  push_back(std::make_pair(L'т', L'Т'));
                  push_back(std::make_pair(L'у', L'У'));
                  push_back(std::make_pair(L'ф', L'Ф'));
                  push_back(std::make_pair(L'х', L'Х'));
                  push_back(std::make_pair(L'ц', L'Ц'));
                  push_back(std::make_pair(L'ч', L'Ч'));
                  push_back(std::make_pair(L'ш', L'Ш'));
                  push_back(std::make_pair(L'щ', L'Щ'));
                  push_back(std::make_pair(L'ъ', L'Ъ'));
                  push_back(std::make_pair(L'ы', L'Ы'));
                  push_back(std::make_pair(L'ь', L'Ь'));
                  push_back(std::make_pair(L'э', L'Э'));
                  push_back(std::make_pair(L'ю', L'Ю'));
                  push_back(std::make_pair(L'я', L'Я'));

                  // Сортировка необходима из-за нестандартного положения буквы 'ё' в таблице символов
                  std::sort(begin(), end(), [](const_reference ref1, const_reference ref2) -> bool
                  {
                     return (ref1.first < ref2.first);
                  });
               }
            } vec;
      
            auto it = std::lower_bound(vec.begin(), vec.end(), __c, 
               [](toupper_vec::const_reference ref, wchar_t __c) -> bool
            {
               return (ref.first < __c);
            });
      
            if (it != vec.end() && it->first == __c)
            {
               return it->second;
            }
      
            return _base::do_toupper(__c);
         }
      
         virtual const wchar_t* do_toupper(wchar_t* __lo, const wchar_t* __hi) const override
         {
            for (wchar_t* curr = __lo; curr != __hi; ++curr)
            {
               *curr = do_toupper(*curr);
            }
            return __lo;
         }
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Код: Выделить всё

      
         virtual wchar_t do_tolower(wchar_t __c) const override
         {
            using tolower_vec_base = std::vector<std: :p air<wchar_t, wchar_t>>;

            static class tolower_vec : public tolower_vec_base
            {
            public:
               tolower_vec() : tolower_vec_base()
               {
                  reserve(33);
                  push_back(std::make_pair(L'А', L'а'));
                  push_back(std::make_pair(L'Б', L'б'));
                  push_back(std::make_pair(L'В', L'в'));
                  push_back(std::make_pair(L'Г', L'г'));
                  push_back(std::make_pair(L'Д', L'д'));
                  push_back(std::make_pair(L'Е', L'е'));
                  push_back(std::make_pair(L'Ё', L'ё'));
                  push_back(std::make_pair(L'Ж', L'ж'));
                  push_back(std::make_pair(L'З', L'з'));
                  push_back(std::make_pair(L'И', L'и'));
                  push_back(std::make_pair(L'Й', L'й'));
                  push_back(std::make_pair(L'К', L'к'));
                  push_back(std::make_pair(L'Л', L'л'));
                  push_back(std::make_pair(L'М', L'м'));
                  push_back(std::make_pair(L'Н', L'н'));
                  push_back(std::make_pair(L'О', L'о'));
                  push_back(std::make_pair(L'П', L'п'));
                  push_back(std::make_pair(L'Р', L'р'));
                  push_back(std::make_pair(L'С', L'с'));
                  push_back(std::make_pair(L'Т', L'т'));
                  push_back(std::make_pair(L'У', L'у'));
                  push_back(std::make_pair(L'Ф', L'ф'));
                  push_back(std::make_pair(L'Х', L'х'));
                  push_back(std::make_pair(L'Ц', L'ц'));
                  push_back(std::make_pair(L'Ч', L'ч'));
                  push_back(std::make_pair(L'Ш', L'ш'));
                  push_back(std::make_pair(L'Щ', L'щ'));
                  push_back(std::make_pair(L'Ъ', L'ъ'));
                  push_back(std::make_pair(L'Ы', L'ы'));
                  push_back(std::make_pair(L'Ь', L'ь'));
                  push_back(std::make_pair(L'Э', L'э'));
                  push_back(std::make_pair(L'Ю', L'ю'));
                  push_back(std::make_pair(L'Я', L'я'));

                  // Сортировка необходима из-за нестандартного положения буквы 'ё' в таблице символов
                  std::sort(begin(), end(), [](const_reference ref1, const_reference ref2) -> bool
                  {
                     return (ref1.first < ref2.first);
                  });
               }
            } vec;
      
            auto it = std::lower_bound(vec.begin(), vec.end(), __c, 
               [](tolower_vec::const_reference ref, wchar_t __c) -> bool
            {
               return (ref.first < __c);
            });
      
            if (it != vec.end() && it->first == __c)
            {
               return it->second;
            }
      
            return _base::do_tolower(__c);
         }
      
         virtual const wchar_t* do_tolower(wchar_t* __lo, const wchar_t* __hi) const override
         {
            for (wchar_t* curr = __lo; curr != __hi; ++curr)
            {
               *curr = do_tolower(*curr);
            }
            return __lo;
         }
      };
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить