Учитывая string foo
, я написал ответы о том, как использовать cctype
tolower
для преобразования символов в нижний регистр
transform(cbegin(foo), cend(foo), begin(foo), static_cast<int (*)(int)>(tolower))
Но я начал рассматривать locale
tolower
, который можно использовать следующим образом:
use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), foo.size()));
- Есть ли причина предпочесть один из них над другим?
- Отличается ли их функциональность вообще?
- Я имею в виду, кроме того, что
tolower
принимает и возвращает int
, который, я полагаю, является лишь некоторым устаревшим материалом C?
Ответ 1
Следует отметить, что разработчики языка знали cctype
tolower
, когда был создан locale
tolower
. Он улучшен двумя основными способами:
- Как упоминается в progressive_overload answer, версия
locale
допускает использование facet ctype
, даже измененного пользователем, без необходимости перетасовки новый LC_CTYPE
через setlocale
и восстановление предыдущего LC_CTYPE
- Из раздела 7.1.6.2 [dcl.type.simple] 3:
Определяется реализацией, представлены ли объекты типа char
в виде подписанных или неподписанных величин. Спецификатор signed
заставляет char
объекты подписываться
Что создает потенциал для undefined поведения с cctype
версией tolower
, если он аргумент:
Не представляется в качестве unsigned char
и не равно EOF
Таким образом, существует дополнительный вход и выход static_cast
, требуемый версией cctype
tolower
, предоставляющей:
transform(cbegin(foo), cend(foo), begin(foo), [](const unsigned char i){ return tolower(i); });
Так как версия locale
работает непосредственно на char
, нет необходимости в преобразовании типа.
Итак, если вам не нужно выполнять преобразование в другом facet ctype
, он просто становится вопросом стиля, предпочитаете ли вы transform
лямбда, требуемую версией cctype
, или вы предпочитаете версию locale
:
use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), size(foo)));
Ответ 2
К сожалению, оба одинаково плохи. Хотя std::string
претендует на то, что это строка, закодированная в utf-8, но не методы/функции (в том числе tolower), действительно знают utf-8. Таким образом, tolower
/tolower
+ locale может работать с символами, которые являются одиночными байтами (= ASCII), они будут терпеть неудачу для каждого другого набора языков.
В Linux я бы использовал библиотеку ICU. В Windows я бы использовал функцию CharUpper
.
Ответ 3
В первом случае (cctype) языковой стандарт задается неявно:
Преобразует заданный символ в нижний регистр в соответствии с символом правила преобразования, определенные в текущем установленном языковом языке C.
http://en.cppreference.com/w/cpp/string/byte/tolower
Во втором (локальном) случае вам нужно явно установить локаль:
Преобразует параметр c в его нижний регистр, если c является прописным буквы и имеет эквивалент в нижнем регистре, как определено ctype грань locale loc. Если такое преобразование невозможно, значение возвращается с неизменным.
http://www.cplusplus.com/reference/locale/tolower/