Как использовать польские специальные буквы в С++?

У меня есть строка, которую я хочу сделать заглавной, но она может содержать польские специальные буквы (ą, ć, ę, ł, ń, ó, ś, ż, ź). Функция transform(string.begin(), string.end(), string.begin(), ::toupper); пишет только латинский алфавит с заглавной буквы, поэтому я написал такую ​​функцию:


    string to_upper(string nazwa)
    {
        transform(nazwa.begin(), nazwa.end(), nazwa.begin(), ::toupper);

        for (int i = 0; i < (int)nazwa.size(); i++)
        {
            switch(nazwa[i])
            {
                case u'ą':
                {
                    nazwa[i] = u'Ą';
                    break;
                }
                case u'ć':
                {
                    nazwa[i] = u'Ć';
                    break;
                }
                case u'ę':
                {
                    nazwa[i] = u'Ę';
                    break;
                }
                case u'ó':
                {
                    nazwa[i] = u'Ó';
                    break;
                }
                case u'ł':
                {
                    nazwa[i] = u'Ł';
                    break;
                }
                case u'ń':
                {
                    nazwa[i] = u'Ń';
                    break;
                }
                case u'ś':
                {
                    nazwa[i] = u'Ś';
                    break;
                }
                case u'ż':
                {
                    nazwa[i] = u'Ż';
                    break;
                }
                case u'ź':
                {
                    nazwa[i] = u'Ź';
                    break;
                }
            }
        }

        return nazwa;
    }

Я также пытался использовать if вместо switch, но это ничего не меняет. В Qt Creator рядом с каждой заглавной буквой, которую нужно вставить, кроме u'Ó', выдает аналогичную ошибку: Implicit conversion from 'char16_t' to 'std::basic_string<char>::value_type' (aka 'char') changes value from 260 to 4 (это от u'Ą'). После запуска программы символы в строке не меняются местами.

Вам нужно будет использовать кодовые точки Unicode. Поскольку эти буквы не представлены в таблице ASCII. Взгляните на stackoverflow.com/questions/331690 и stackoverflow.com/questions/3010739

binaryescape 02.08.2023 11:43

@Yunnosch OP упомянул об этом в вопросе. Это будет работать, только если вы установите локаль, которая поддерживает польские символы.

Yksisarvinen 02.08.2023 11:56

У меня есть это, и оно все еще не работает: `setlocale(LC_ALL, "pl_PL"); unsigned char c = nazwa[i]; nazwa[i] = toupper(c);`

Greg 02.08.2023 12:04

@Greg - вам нужно использовать либо (шаблон) std::toupper(), который принимает const std::locale & в качестве второго аргумента, либо std::towupper(). В любом случае вам нужно будет передать широкий символ (например, wchar_t не тип char) Имейте в виду, что оба сопоставляют только один символ с одним символом (например, их нельзя использовать, если преобразование в верхний регистр сопоставляет один символ с парой символов ).

Peter 02.08.2023 12:33

Вам нужно начать с решения, какой кодировкой закодирован string. std::string не подразумевает какой-либо конкретной кодировки.

user17732522 02.08.2023 12:34

@Yksisarvinen Спасибо, пропустил из-за отсутствия (). Виноват. И я не знал о зависимости от локали. (Рад, что спросил, вместо того, чтобы извергать неправильные нерешения.... ;-))

Yunnosch 02.08.2023 12:46

@Peter - у меня есть это, и ни одна из двух последних строк не работает (я не использую обе одновременно), я все равно получаю строчную букву: setlocale(LC_ALL, "pl_PL"); wchar_t c = nazwa[i]; nazwa[i] = toupper(c, locale("pl_PL")); nazwa[i] = towupper(c);

Greg 02.08.2023 12:52

Какую кодировку вы используете? 8859-2? Юникод UTF-8 (65001)? Windows-1250? Мак-10029?

Eljay 02.08.2023 13:22

@RedStoneMatt - я уже пробовал это, это не работает, для «ą» это дает мне умлаут с большой буквы.

Greg 02.08.2023 13:28

@Eljay - я думаю, что использую UTF-8

Greg 02.08.2023 13:28

Другой вариант — использовать библиотеку ICU.

Eljay 02.08.2023 14:16

Какая у вас ОС и компилятор? А где вы берете свою струну? (Терминал, файл на диске, сетевое подключение, что-то еще?)

n. m. could be an AI 02.08.2023 14:28

Что еще более важно, зачем вам нужно использовать строку с заглавной буквы? Большинству людей, которые думают, что им нужно использовать заглавные буквы в строках, на самом деле требуется только сопоставление регистра, что является гораздо более простой проблемой (в целом использование заглавных букв на удивление сложно, если вам нужно иметь дело со многими языками).

n. m. could be an AI 02.08.2023 14:43

@Greg «Я уже пробовал это, это не работает, для «ą» это дает мне умляут с большой буквы», вероятно, потому, что вы вычли 1 из обоих байтов, составляющих ą. Пожалуйста, смотрите мой полный ответ ниже, он объясняет, как UTF-8 работает с вашим конкретным случаем, и дает функцию, которая должна выполнять эту работу за вас.

RedStoneMatt 02.08.2023 14:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
15
101
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Самый простой способ справиться с этим — использовать широкую строку. Единственная ловушка - правильная обработка кодировки/локали.

Итак, попробуйте следующее:

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

int main()
try {
    std::locale cLocale{ "C.UTF-8" };
    std::locale::global(cLocale);

    std::locale sys { "" };
    std::wcin.imbue(sys);
    std::wcout.imbue(sys);

    std::wstring line;
    while (getline(std::wcin, line)) {
        std::transform(line.begin(), line.end(), line.begin(), [&cLocale](auto ch) { return std::toupper(ch, cLocale); });
        std::wcout << line << L'\n';
    }
} catch (const std::exception& e) {
    std::cerr << e.what() << '\n';
}

https://godbolt.org/z/3cKaEeW3z

Сейчас:

  • cLocale определяет локаль, которая будет использоваться стандартной библиотекой при взаимодействии с вашей программой.
  • sys — это языковой стандарт системы, который определяет, какую кодировку следует использовать для входных и выходных потоков. Обратите внимание, какой перегружатель используется.

Тот же код должен работать с std::string и std::cinstd::cout, только если вы используете однобайтовую кодировку, которая работает для польского языка. В таком случае вы должны изменить строку в cLocale на:

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

int main()
try {
    std::locale cLocale{ ".1250" };
    std::locale::global(cLocale);

    std::locale sys { "" };
    std::cin.imbue(sys);
    std::cout.imbue(sys);

    std::string line;
    while (getline(std::cin, line)) {
        std::transform(line.begin(), line.end(), line.begin(), [&cLocale](auto ch) { return std::toupper(ch, cLocale); });
        std::cout << line << '\n';
    }
} catch (const std::exception& e) {
    std::cerr << e.what() << '\n';
}

Обратите внимание, что это имя локали зависит от платформы и компилятора, а также система должна быть настроена для работы. Выше работает в Windows с MSVC (я проверял это). Не могу продемонстрировать это, так как нет онлайн-компилятора, поддерживающего польскую локаль.

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

Я получаю эту ошибку: collate_byname<char>::collate_byname не удалось построить для .1250

Greg 02.08.2023 13:56

Вы не написали, какую ОС и компилятор вы использовали. Я написал, что это зависит от платформы и компилятора и протестировал это с помощью MSVC в Windows 10 с настроенной поддержкой польского языка. Версия с широкими строками должна просто работать.

Marek R 02.08.2023 13:57

Работаю на MacOS в Qt Creator

Greg 02.08.2023 13:58

Затем введите терминал locale -a, чтобы увидеть возможные названия локалей.

Marek R 02.08.2023 13:58

В моей MacOS есть pl_PL.ISO8859-2, что эквивалентно кодовой странице Windows 1250.

Marek R 02.08.2023 14:00

Хорошо, не работает на MacOS :(.

Marek R 02.08.2023 14:02

На моей машине с MacOS широкая строковая версия не работает, но странным образом. Он дублирует символы и добавляет впереди немного мусора, по крайней мере, повторяющиеся символы являются правильными в верхнем регистре. Поддержка локалей для C++ отстой.

Marek R 02.08.2023 14:11
Есть небольшая проблема с вашим подходом. Он не работает с libc++, поэтому пользователи MacOS, привязанные к компилятору, поставляемому с ОС, могут захотеть найти другое решение.
n. m. could be an AI 02.08.2023 14:35

@MarekR Это вина libc++. У него нет рабочего wcin/wcout.

n. m. could be an AI 02.08.2023 16:22
Ответ принят как подходящий

Источник вашей проблемы

std::string хранит символы как chars, длина которых составляет один байт, поэтому их значение может быть только от 0 до 255.

Это делает невозможным хранение u'ą' в одном char, например, поскольку значение Юникода для ą равно 0x105 (= 261 в десятичном виде, что больше, чем 255).

Чтобы избежать этой проблемы, люди изобрели UTF-8, стандарт кодирования символов, который позволяет кодировать любые символы Unicode в виде байтов. Разумеется, для кодирования символов с более высоким значением потребуется несколько байтов.

Весьма вероятно, что ваши символы std::string закодированы в UTF-8. (Я говорю очень вероятно, потому что ваш код прямо не указывает на это, но почти на 100% уверен, что это так, потому что это единственный универсальный способ кодирования букв с диакритическими знаками в строках на основе char. Чтобы быть абсолютно на 100% конечно, вам нужно проверить код Qt, так как это похоже на то, что вы используете)

Результатом этого является то, что вы не можете просто использовать for для перебора char ваших std::string так, как вы есть, потому что вы в основном предполагаете, что один char равен одной букве, что просто не так.

Например, в случае ą он будет закодирован как байты C4 85, поэтому у вас будет один char со значением 0xC4 (= 196), за которым следует другой char со значением 0x85 (= 133).


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

Часть Latin Extended-A таблицы Unicode ( архив), к счастью, показывает нам, что эти специальные заглавные буквы идут прямо перед их строчными копиями.

Более того, мы можем видеть, что:

  • От индекса Unicode от 0x100 до 0x137 (включая оба) строчные буквы являются нечетными индексами.
  • От 0x139 до 0x148 (включая оба) строчные буквы являются четными индексами.
  • От 0x14A до 0x177 (включая оба) строчные буквы являются нечетными индексами.
  • От 0x179 до 0x17E (включая оба) строчные буквы являются четными индексами.

Это облегчит преобразование строчных кодовых точек в прописные, поскольку все, что нам нужно сделать, это проверить, соответствует ли индекс символа строчному, и если да, вычесть из него единицу, чтобы сделать его прописным.


Кодирование одного из этих символов в UTF-8

Чтобы закодировать их в UTF-8 (источник):

  • Преобразуйте кодовую точку (значение Unicode, если вы предпочитаете так говорить) в двоичном формате.
  • Первый байт вашего символа в кодировке UTF-8 будет иметь двоичное значение 110xxxxx, замените xxxxx старшими пятью байтами двоичного кода символа.
  • Второй байт будет иметь двоичное значение 10xxxxxx, замените xxxxxx младшими шестью байтами двоичной кодовой точки символа.

Итак, для ą значение 0x105 в шестнадцатеричном формате, поэтому 00100000101 в двоичном формате.

Тогда значение первого байта равно 11000100 (= 0xC4).

Тогда значение второго байта равно 10000101 (= 0x85).

Обратите внимание, что этот «метод» кодирования работает, потому что символы, которые вы хотите использовать с заглавными буквами, имеют свое значение (кодовую точку) между 0x80 и 0x7FF. Оно меняется в зависимости от того, насколько велико значение, см. документацию здесь.


Исправление вашего кода

Я переписал вашу функцию to_upper в соответствии с тем, что я написал до сих пор:

string to_upper(string nazwa)
{
    for (int i = 0; i < (int)nazwa.size(); i++)
    {
        // Getting the current character we are working with
        char chr1 = nazwa[i];

        // We want to find UTF-8-encoded polish letters here
        // So we are looking for a character that has first three bits set to 110,
        // as all polish letters encoded in UTF-8 are in UTF-8 Class 1 and therefore
        // are two bytes long, the first byte being of binary value 110xxxxx
        if (((chr1 >> 5) & 0b111) != 0b110) {
            nazwa[i] = toupper(chr1); // Do the std toupper here for regular characters
            continue;
        }

        // If we are here, then the character we are dealing with is two bytes long, so get its value.
        // We won't need to check for that second byte during next iteration, so we increment i
        i++;
        char chr2 = nazwa[i];

        // Get the unicode value of the encoded character
        uint16_t fullChr = ((chr1 & 0b11111) << 6) | (chr2 & 0b111111);

        // Get the various conditions to check for lowercase code points
        bool lowercaseIsOdd =  (fullChr >= 0x100 && fullChr <= 0x137) || (fullChr >= 0x14A && fullChr <= 0x177);
        bool lowercaseIsEven = (fullChr >= 0x139 && fullChr <= 0x148) || (fullChr >= 0x179 && fullChr <= 0x17E);
        bool chrIndexIsOdd =   (fullChr % 2) == 1;

        // Depending of whether the code point needs to be odd or even to be lowercase and depending of if the code point
        // is odd or even, decrease it by one to make it uppercase
        if ((lowercaseIsOdd && chrIndexIsOdd)
        || (lowercaseIsEven && !chrIndexIsOdd))
            fullChr--;

        // Support for some additional, more commonly used accented letters
        if (fullChr >= 0xE0 && fullChr <= 0xF6)
            fullChr -= 0x20;

        // Re-encode the character point in UTF-8
        nazwa[i-1] = (0b110 << 5) | ((fullChr >> 6) & 0b11111); // We incremented i earlier, so subtract one to edit the first byte of the letter we're encoding
        nazwa[i] = (0b10 << 6) | (fullChr & 0b111111);
    }

    return nazwa;
}

Примечание: не забудьте #include <cstdint>, чтобы uint16_t работало.

Примечание 2: я добавил поддержку некоторых букв Latin 1 Supplement ( архив), потому что вы просили об этом в комментариях. Хотя мы вычитаем 0x20 из строчных кодовых точек, чтобы получить прописные, это почти тот же принцип, что и для других букв, которые я рассмотрел в этом ответе.

Я включил много комментариев в свой код, пожалуйста, прочтите их для лучшего понимания.

Я протестировал его со строкой "ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽž", и он преобразовал ее в "ĀĀĂĂĄĄĆĆĈĈĊĊČČĎĎĐĐĒĒĔĔĖĖĘĘĚĚĜĜĞĞĠĠĢĢĤĤĦĦĨĨĪĪĬĬĮĮİİIJIJĴĴĶĶĸĹĹĻĻĽĽĿĿŁŁŃŃŅŅŇŇŊŊŌŌŎŎŐŐŒŒŔŔŖŖŘŘŚŚŜŜŞŞŠŠŢŢŤŤŦŦŨŨŪŪŬŬŮŮŰŰŲŲŴŴŶŶŸŹŹŻŻŽŽ", так что все работает отлично:

int main() {
    string str1 = "ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽž";
    string str2 = to_upper(str1);

    printf("str1: %s\n", str1.c_str());
    printf("str2: %s\n", str2.c_str());
}

Примечание. Все терминалы используют UTF-8 по умолчанию, метки Qt также, в основном ВСЕ используют UTF-8, КРОМЕ Windows CMD, поэтому, если вы тестируете приведенный выше код на Windows CMD или Powershell, вам необходимо изменить их на UTF. -8 с помощью команды chcp 65001 или добавив вызов Windows API для изменения кодировки CMD при выполнении кода.

Примечание 2. Когда вы пишете необработанные строки непосредственно в своем коде, ваш компилятор по умолчанию кодирует их в UTF-8. Вот почему моя версия функции to_upper работает с польскими буквами, написанными непосредственно в коде без дальнейших модификаций. Когда я говорю, что ВСЕ использует UTF-8, я имею в виду именно это.

Примечание 3. Я сохранил его, чтобы не создавать проблем с вашим текущим кодом, но вы используете string вместо std::string, подразумевая, что где-то в вашем коде есть using namespace std;. В этом случае см. Почему «использование пространства имен std;» считается плохой практикой?


Обратите внимание на другие ответы

Пожалуйста, имейте в виду, что мой ответ очень специфичен для вашего случая. Он направлен на то, чтобы, как вы и просили, сделать польские буквы заглавными.

Другие ответы основаны на функциях std, которые, по-видимому, более универсальны и работают со всеми языками, поэтому я предлагаю вам взглянуть на них.

Всегда лучше полагаться на существующие функции, чем изобретать велосипед, но я думаю, что также хорошо иметь самодельную альтернативу, которая может быть проще для понимания, а иногда и более эффективна.

«Это делает невозможным хранение u'ą', например, в одном символе». Люди делали это задолго до появления Unicode и делают это до сих пор (см. Кодовые страницы Windows и т. д.). Не то чтобы это хороший способ решить проблему в 2023 году, но, безусловно, существующий и в какой-то степени работающий способ.

n. m. could be an AI 02.08.2023 14:27

@n.m.couldbeanAI Кодовые страницы Windows не только считаются ОЧЕНЬ плохой практикой, но и (очевидно) предназначены только для Windows. OP сказал, что они используют Qt Creator, подразумевая, что разрабатываемое ими приложение может быть универсальным, поэтому UTF-8 является обязательным. Но да, действительно, различные расширения ASCII добавили поддержку такого типа символов, но она очень ограничена, поскольку эти расширения по-прежнему ограничены пределом значений 0-255 для каждого символа. Таким образом, они добавляют символы для значений от 128 до 255, но всегда будут неподдерживаемые символы. UTF-8 от этого совершенно не страдает.

RedStoneMatt 02.08.2023 14:32

Смысл UTF-8 в том, что он поддерживает все символы Unicode, которые теоретически могут иметь такое большое значение, какое мы хотим. На данный момент существует только четыре диапазона символов, но при необходимости их можно будет добавить в один прекрасный день. Кроме того, поскольку, как я упоминал в своем предыдущем комментарии, OP использует Qt, UTF-8, вероятно, является единственным способом заставить эти акцентированные символы работать в конкретном случае OP, потому что им, скорее всего, нужна строка, чтобы оставаться в кодировке UTF-8 для Qt понять это.

RedStoneMatt 02.08.2023 14:36

«Смысл UTF-8 в том, что он поддерживает все символы Юникода». Продолжается с жестко закодированной вручную таблицей капитализации для небольшой части Юникода и неправильной для загрузки (посмотрите на свой ıŚśŜŝŞ).

n. m. could be an AI 02.08.2023 15:02

OP запросил полированные символы, поэтому я написал свой код только для этого. Потребуется вечность, чтобы пройтись по всем строчным символам в таблице Unicode и преобразовать их в прописные. Вы правы из-за ошибки в конце строки, которую я включил в свой ответ! Я был недостаточно внимателен, я это исправлю. Спасибо, что сообщили об этом, хотя я бы предпочел, чтобы вы сказали это менее агрессивно :)

RedStoneMatt 02.08.2023 15:04

«Потребуется целая вечность, чтобы просмотреть все символы нижнего регистра в таблице Unicode и преобразовать их в верхний регистр». Вот почему вы используете таблицы, которые уже скомпилированы для вас и предустановлены на вашем компьютере.

n. m. could be an AI 02.08.2023 15:08

@n.m.couldbeanAI В настоящее время изучает неправильные буквы; по какой-то причине кажется, что значение второго байта из них неверно при получении их из строки. Это довольно странно, потребуется некоторое время, чтобы выяснить, как это исправить. Кроме того, если вы знаете лучший способ ответить на вопрос ОП, то, пожалуйста, напишите на него ответ, гораздо лучше будет объяснить вашу точку зрения, чем комментарии. Я всегда готов узнать больше, поэтому не стесняйтесь показывать нам, как использовать эти таблицы, я даже не знал, что это так, и для этого и нужны ответы.

RedStoneMatt 02.08.2023 15:18

Просто не пишите свое собственное преобразование регистра. Используйте стандартный. Это все необходимое исправление.

n. m. could be an AI 02.08.2023 15:28

Исправлена ​​проблема, о которой вы сообщили @n.m.couldbeanAI, виновником на самом деле был stdtoupper, который превращал символы со значениями 0x9C и 0x9E в 0x8C и 0x8E соответственно, тем самым нарушая мою функцию. Я исправил это, сделав вызовы to_upper только для обычных символов, что также делает код менее сложным, поскольку теперь он выполняет итерацию по строке только один раз вместо двух.

RedStoneMatt 02.08.2023 15:29

"Используйте стандартный", тогда ответьте пожалуйста и покажите стандартный способ. Я копался в stackoverflow и нашел только «Стандартных способов нет» и «Используйте какую-нибудь библиотеку, верхний регистр не является точным термином». Если вы знаете решение, пожалуйста, дайте решение, в этом смысл этого сайта.

RedStoneMatt 02.08.2023 15:31

Я попросил разъяснения у ОП и могу ответить, когда получу его. Между тем, другой ответ работает лучше вашего и использует стандартные средства. Попробуй это.

n. m. could be an AI 02.08.2023 15:47

@n.m.couldbeanAI Я попробую другой ответ. Однако, пожалуйста, посмотрите комментарии под другим ответом, кажется, что это не сработает для OP.

RedStoneMatt 02.08.2023 15:56

Это не сработает, если OP нужно будет прочитать символы со стандартного ввода, о котором мы не знаем. Некоторые подобные методы будут работать. Я попросил разъяснений, но пока их нет.

n. m. could be an AI 02.08.2023 16:18

@RedStoneMatt - Спасибо, это в основном решает мою проблему, но пара 'ó' и 'Ó' (0xD3, 0xF3) не работает, есть ли способ изменить вашу программу, чтобы поменять их местами, или это совершенно другое?

Greg 02.08.2023 16:44
Это должно работать на Mac для всех языков, за исключением странных случаев, таких как турецкий I. Он использует устаревшее средство C++ (codecvt_utf8), если вам это не нравится, замените любым другим utf8 в utf32 и процедуры обратного преобразования . Также замените свою собственную локаль, если хотите.
n. m. could be an AI 02.08.2023 16:50

@Greg Непосредственно перед комментарием // Re-encode the character point in UTF-8 в моем коде добавьте if (fullChr >= 0xE0 && fullChr <= 0xF6) fullChr -= 0x20;, это добавит поддержку набора букв Дополнения к латинице 1, включая ó. Они не являются эксклюзивными для польского языка, поэтому я не включил их в свой ответ. Как я упоминал в одном из своих комментариев, поддержка всех строчных букв Unicode заняла бы целую вечность и привела бы к очень большой функции.

RedStoneMatt 02.08.2023 17:10

Возможно, вы также обратите внимание на предложение @n.m.couldbeanAI, если оно сработает для вас, Грег.

RedStoneMatt 02.08.2023 17:13

Я обновил свой ответ по вашему запросу, Грег.

RedStoneMatt 02.08.2023 17:22

Спасибо @RedStoneMatt, это решает все мои проблемы с этим.

Greg 02.08.2023 18:30

Это должно работать на большинстве систем Unix-y, за исключением странных случаев, таких как турецкий I и, возможно, немецкий ß.

#include <clocale>
#include <locale>
#include <iostream>
#include <string>
#include <cwctype>
#include <codecvt>

inline std::wstring stow(const std::string& p)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> wconv;
    return wconv.from_bytes(p);
}

inline std::string wtos(const std::wstring& p)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> wconv;
    return wconv.to_bytes(p);
}


int main()
{
    std::locale loc("");

    // AFAICT the calls below are optional on a Mac 
    // for this particular task but it could be a 
    // good idea to use them anyway
    // std::setlocale(LC_ALL, "");
    // std::locale::global(loc);
    // std::cin.imbue(loc);
    // std::cout.imbue(loc);

    std::string s;
    std::getline(std::cin, s);

    std::wstring w = stow(s);
    for (auto& c: w)
    {
        c = std::toupper(c, loc);
    }

    std::cout << wtos(w) << "\n";
}

Обратите внимание, что он использует устаревшие средства C++ для преобразования кода UTF-8. Если вас это беспокоит, подставьте любые преобразователи UTF-8 в UTF-32 и обратно в stow и wtos. Также не стесняйтесь заменять локаль, существующую в вашей системе (может быть "pl_PL.UTF-8" или аналогичная).,

Другие вопросы по теме