Теперь Кью работает в режиме чтения

Мы сохранили весь контент, но добавить что-то новое уже нельзя

C++. Как получить базовый символ из utf-8, удалив модификаторы?

Когда разбираешь строку, состоящую из английских символов, проблем нет - каждый символ соответствует тому, каким он был введён, и количество символов соответствует исходному.
На самом деле я просто хочу решить проблему с длиной строки, содержащей символы с дополнительными знаками и кириллицу.
Что-то похожее происходит, когда выводишь строку на консоль - выводятся только базовые. Хочу применить похожее к строке. Это возможно сделать?
И да, с выводом на консоль данный вопрос отношения не имеет!
ПрограммированиеC+++2
DJ Ruben
  ·   · 808
Программист, математик, инженер.  · 1 апр 2023
Вопрос на самом деле сильно интереснее чем кажется.
Вообще, базовые вещи в юникоде в целом, и в utf8 в частности:
  • Сам по себе юникод - это абстракция - абстрактные символы в "юникоде" которые можно кодировать в заданную кодировку (utf8, utf16, utf32, codepoint и т.д)
  • Символы имеют переменную длину (utf8 - 1-4 байта, utf16 - 2-4 байта, utf32 - 4 байта);
  • Символы юникода могут представлять собой как один символ, так и комбинированные символы (символ + модификаторы аксантов + модификаторы цвета + модификаторы направления чтения и ещё множество модификаторов символов и̸͙͇̔͘̚͜ к̵͚̫̔̾̾а̸͇͕͚͐̓͆ж̴̢͉̼̾̔д̵̙͙̈́̀̕͜ӹ̵̙͍͍́͑͊й̸͙̻͉̿̀̓ с̴̫͔͉̒̀͝и̴̞̞́̀̒м̵̻͕̘̀̀̚в̸̘̠̫́͛̀о̸̝̞̟͆͘л̸͙̺̾͌͒͜ в̴͖͐͌̈́͜͜ э̵̺̞͖̿͛͘т̴̻̝̟͋͆͝о̸͍̙̼̔̒̕м̴̢͇͎͛̓̽ т̴̟͚̘̒̕͠ё̵̟͚́̾̓͜к̵͕̟̝̔͋̿с̴͖͔̪̔̓͝т̸͓̠̟͑͐ё̵̘̙͎́͐̕ ӥ̴̺͖͍́̈́͝м̵̦͓̝͛͒͝е̸̢͎͔̔̐͛е̵̢͔͙̚͝т̸͖͉̼̿̈́͝ 3̵͖̠͓̈́͆-̴̼̝͔̓̕͝2̴̻̠͎͆̀̾0̸̢̺̦̽̈́̿ п̴̞̙̪͊̓͘р̵̺͕̠͛͋͒и̸̝̝̟͊̈́̿ц̴̢̺͇̔́͐е̵͙̦̼̒͊п̸̪͚͇̒͆͝л̸͕͍̦͌̓͊ё̵͉͙͉́͛̔н̸̘̠͒̔͒н̸̫͔̻̈́͝ӹ̵̡͇̻́̽̓х̸͙̝̟͆͋̓ м̸̪̘͇͊͒͝о̸̝͕̘̀͛̓д̴͍͎͓̓͆̐и̸̘̻̚͜͝ф̸̢̻͓͊͐и̸̟̟̙̿̒̐к̵̝̼͙̾̈́̓а̸͓̞͙́͒͝т̸͖̦̒̽̀͜о̸̡̪̺͐͌̚р̴̢̞̘͛̐͝о̸̦̪͔͆͐̈́в̵̡̡͍͋͆͝,̵̪͉̪͑̔̕ о̴̞͚̔͋͐с̵͕͎̦͑̕т̵̢̞͌̈́̕͜а̴̫̦̠͆͋̚в̸͙̺͐̾͘͜а̴̠͉͖̿̀̕я̸̟͉͚̿́͠с̸̝̟͋͋͘ь̵̻͇̓́͝ о̸̻͚͐̀д̵̦͚͖͌̒͝н̴̝̺͎͋͠͝ӥ̵͇̺͕́͆̽м̴̡̼͒̚ с̸͔̪͖̀͌͝и̴͇̼̼̒̚͝м̸̦̟̔́͘͜в̴͍̺͚͋̈́͘о̵̦͇̔͌̐л̵̟̻͋̾́͜ӧ̸͕͕͖́͝м̵̡͚͎̀̾̔ с̴̟̼͕̔͐̚ м̸̢͖̼̀͒о̴̢͉̿͑́д̴̪̠̙́͋͛и̵̡͕̽͐̚ф̸̻̦͓̽́̚и̴̝̘͍͌̿͘к̴̡̡͖̔̔̓а̵͕͖̝͊́̽т̵̡͉͙̐͐̚о̸͍͖̽͊͐͜р̵͖͍͕͒̒͛а̸͔̙̽̈́͛м̴͎͚̼̿͛̕и̴̺͔̔̾̐͜.̸̺͍͕͒͘͠), и есть две операции - композиция (поиск для символов с добавленными модификаторами эквивалента в виде одного символа, вместо "сосисочка" + "картошечка" - "картошка с сосиской") и декомпозиция — разбиение "картошки с сосиской" на "картошку" и "сосиску"). Кстати, в контексте юникода, модификаторы означают именно это, а не что-то ещё.
  • Для работы с юникодом как правило выделяется или отдельный класс, или отдельный набор функций. std::string НЕ работает с юникодом, он работает с байтами, соответственно какой-нибудь string.length() вернёт количество байт в массиве, а не количество символов юникода. Для того же, чтобы узнать длину массива байт в utf8, нужно по нему пробежать. В C++ 20 добавили класс std::u8string, который можно использовать примерно как:
    #include <iostream>
    #include <string> 

        std::u8string text {u8"Это текст в юникоде!"};
        std::u8cout « text « std::endl;
    Соответственно, u8string.length() должна вывести длину в символах юникода.
    Но не у всех библиотек имеется поддержка utf8-строк.
  • Для работы в консоли (cmd) под Windows, её саму ещё надо переключить в режим работы с юникодом, как простейший костыльный вариант - system("chcp 65001") в начале исполнения программы, в противном случае будет использована однобайтная кодировка cp1251, и при выводе юникода будут отображены кракозябры. 
  • Ну, и экскурсионная статья по теме: https://habr.com/ru/sandbox/47663/
Интересно. GCC последних версий (со включенным -Wall -std=gnu++2a) не считает std::u8string стандартной... Читать дальше