ТЛ; др
Используйте библиотеку 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 I DOTLESS I) является ожидаемым результатом (который, опять же, составляет более одного байта в кодировке UTF-8). Еще один пример - греческая сигма , прописные '∑'
, строчные 'σ'
... за исключением конца слова, где оно находится 'ς'
.
Так, любое преобразование, которое работает с символом за раз или, что еще хуже, с байтом за раз, нарушается по замыслу.
Тогда есть смысл, что стандартная библиотека, для чего она это способен делать, в зависимости от того , локали поддерживается на машине ваше программное обеспечение работает на ... и что делать , если это не так ?
Так что вы действительно ищете строковый класс, который способен справиться со всем этим правильно, и это не какой-либо из std::basic_string<>
вариантов .
(Примечание C ++ 11: std::u16string
и std::u32string
это лучше ., Но все еще не совершенны C ++ 20 принес std::u8string
, но все это сделать , это указать кодировку во многих других отношениях они все еще остаются в неведении о механике Unicode, как нормализация, обобщению, ... .)
Хотя Boost выглядит неплохо, с точки зрения API, Boost.Locale по сути является оболочкой для ICU .Если Boost скомпилирован с поддержкой ICU ... если нет, Boost.Locale ограничен поддержкой локали, скомпилированной для стандартной библиотеки.
И поверьте мне, заставить Boost компилироваться с ICU иногда бывает очень больно. (Для Windows нет предварительно скомпилированных двоичных файлов, так что вам придется поставлять их вместе с вашим приложением, и это открывает новую банку с червями ...)
Поэтому лично я бы порекомендовал получить полную поддержку Unicode прямо изо рта лошади и напрямую использовать библиотеку ICU :
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
int main()
{
/* "Odysseus" */
char const * someString = u8"ΟΔΥΣΣΕΥΣ";
icu::UnicodeString someUString( someString, "UTF-8" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale,
// which *does* make a difference (see ı vs. i above).
std::cout << someUString.toLower( "el_GR" ) << "\n";
std::cout << someUString.toUpper( "el_GR" ) << "\n";
return 0;
}
Компиляция (с G ++ в этом примере):
g++ -Wall example.cpp -licuuc -licuio
Это дает:
ὀδυσσεύς
Обратите внимание, что преобразование Σ <-> σ в середине слова и преобразование Σ <-> ς в конце слова. Никакое <algorithm>
решение не может дать вам это.
[1] В 2017 году Совет по немецкой орфографии постановил, что "ẞ" U + 1E9E LATIN CAPITAL LAPTER SHARP S может быть официально использован, как вариант, помимо традиционной конверсии "SS", чтобы избежать двусмысленности, например, в паспортах (где имена пишутся с большой буквы) ). Мой прекрасный пример, устарел по решению комитета ...