Как прописные / строчные символы UTF-8 в C++?

давайте представим, что у меня есть кодировка UTF-8 std::string следующего содержания:

óó

и я хотел бы преобразовать его в следующее:

ÓÓ

В идеале я хочу, чтобы верхний/нижний регистр подход, который я использую, был общим для всего UTF-8. Если это вообще возможно.

исходная последовательность байтов в строке 0xc3b3c3b3 (два байта на символ, и два экземпляра ó) и я хотел бы, чтобы выход в будь 0xc393c393 (два экземпляра Ó). Есть примеры на StackOverflow, но они используют широкие символьные строки и другие ответы скажем, вы не должны использовать широкие символьные строки для UTF-8. Также кажется, что эта проблема может быть очень "сложной" в том, что вывод может зависеть от локали пользователя.

я ожидал просто использовать что-то вроде std::toupper(), но использование действительно непонятно для меня, потому что кажется, что я не просто преобразование одного символа за раз, но целой строки. Кроме того, это пример Ideone я собрал, кажется, показать, что toupper() of 0xc3b3 это просто 0xc3b3, что является неожиданным результатом. Зову setlocale для UTF-8 или ISO8859-1, похоже, не изменяет результат.

я хотел бы получить некоторые рекомендации, если бы вы могли пролить свет на то, что я делаю неправильно или почему мой вопрос/предпосылка неисправна!

2 ответов


нет стандартного способа преобразования Unicode в C++. Есть способы, которые работают на некоторые реализации C++, но стандарт не требует от них этого.

Если вы хотите гарантированное преобразование случая Unicode, вам нужно будет использовать библиотеку, такую как ОИТ или Boost.Locale (aka: ICU с более похожим на C++интерфейсом).


есть несколько примеров в StackOverflow, но они используют широкие символьные строки, а другие ответы говорят, что вы не должны использовать широкие символьные строки для UTF-8.

статья внутри (utf8everywhere) и ответы применяются к Windows. Стандарт C++ требует, чтобы wchar_t быть достаточно широким, чтобы вместить все поддерживаемые кодовые единицы (32-битные), но отлично работает с UTF-8. На Windows, wchar_t является UTF-16, но если вы находитесь в Windows, у вас больше проблем чем просто, если мы будем честными (а именно их ужасающий API).

также кажется, что эта проблема может быть очень "сложной" в том, что вывод может зависеть от локали пользователя.

не совсем так. Задайте локаль внутри кода. Некоторые программы, такие как sort не работает должным образом, если вы не установите языковой стандарт внутри оболочки, например, поэтому бремя на пользователя.

Я ожидал просто использовать что-то вроде std:: toupper(), но использование мне действительно непонятно, потому что кажется, что я не просто конвертирую один символ за раз, а целую строку.

в примере кода используются итераторы. Если вы не хотите конвертировать каждый символ, не делайте этого.

кроме того, этот пример Ideone, который я собрал, кажется, показывает, что toupper() 0xc3b3-это просто 0xc3b3, что является неожиданным результатом. Вызов setlocale в UTF-8 или ISO8859-1, похоже, не изменяет результат.

у вас есть неопределенное поведение. Диапазон unsigned char - это 255. 0xc3b3 способ превосходит.

Я хотел бы получить некоторые рекомендации, если бы вы могли пролить свет на то, что я делаю неправильно или почему мой вопрос/предпосылка неисправна!

этот пример прекрасно работает:

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

int main()
{
    std::setlocale(LC_CTYPE, "en_US.UTF-8"); // the locale will be the UTF-8 enabled English

    std::wstring str = L"óó";

    std::wcout << str << std::endl;

    for (std::wstring::iterator it = str.begin(); it != str.end(); ++it)
        *it = towupper(*it);

    std::wcout << str << std::endl;
}

выходы: ÓÓ