ТЛ; др
Использование библиотеки ICU .
Сначала вы должны ответить на вопрос: какова кодировка вашего std::string
? Это ISO-8859-1? Или, возможно, ISO-8859-8? Или кодовая страница Windows 1252? Знает ли это то, что вы используете для преобразования прописных букв в строчные? (Или это с треском проваливается для символов свыше 0x7f
?)
Если вы используете UTF-8 (единственный разумный выбор среди 8-битных кодировок) с std::string
в качестве контейнера, вы уже обманываете себя, полагая, что вы все еще контролируете вещи, потому что вы храните последовательность многобайтовых символов в контейнере, который не знает о концепции многобайтовой Даже такая простая вещь, как .substr()
- это бомба замедленного действия. (Поскольку разбиение многобайтовой последовательности приведет к неверной (под) строке.)
И как только вы попробуете что-то вроде std::toupper( 'ß' )
, в любое кодирование, у вас возникнут серьезные проблемы. (Поскольку это просто невозможно сделать «правильно» со стандартной библиотекой, которая может доставить только один символ результата, а не "SS"
, необходимый здесь.) [1] Другой пример будет std::tolower( 'I' )
, который должен давать разные результаты в зависимости от локали . В Германии 'i'
будет правильным; в Турции 'ı'
(LATIN SMALL LETTER DOTLESS I) - это ожидаемый результат (который, опять же, составляет более одного байта в кодировке UTF-8).
Тогда есть смысл, что стандартная библиотека зависит от того, какие локали поддерживаются на машине, на которой работает ваше программное обеспечение ... и что вы делаете, если это не так?
То, что вы действительно ищете, - это строковый класс, способный справиться со всем этим правильно, , то есть , а не std::string
.
(примечание C ++ 11: std::u16string
и std::u32string
лучше , но все еще не идеально.)
В то время как Boost выглядит красиво, с точки зрения API, Boost.Locale по сути является оберткой для ICU . Если Boost скомпилирован с поддержкой ICU ... если нет, Boost.Locale ограничен поддержкой локали, скомпилированной для стандартной библиотеки.
И поверьте мне, получение Повышение при компиляции с ICU иногда может быть настоящей болью. (Для Windows нет предварительно скомпилированных двоичных файлов, поэтому вам нужно будет поставлять их вместе с вашим приложением, и , что открывает совершенно новую банку с червями ...)
Так что лично я бы порекомендовал получить полную поддержку Unicode прямо изо рта лошади и напрямую использовать библиотеку ICU :
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
int main()
{
char const * someString = "Eidenges\xe4\xdf";
icu::UnicodeString someUString( someString, "ISO-8859-1" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale.
std::cout << someUString.toLower( "de_DE" ) << "\n";
std::cout << someUString.toUpper( "de_DE" ) << "\n";
return 0;
}
Компиляция (с G ++ в этом примере):
g++ -Wall example.cpp -licuuc -licuio
Это дает:
eidengesäß
EIDENGESÄSS
[1] В 2017 году Совет по немецкой орфографии постановил, что «ẞ» U + 1E9E LATIN CAPITAL LETTER SHARP S может быть официально использован, как вариант, помимо традиционной конверсии «SS», чтобы избежать двусмысленности, например в паспортах (где имена пишутся с большой буквы). Мой прекрасный пример, устарел по решению комитета ...