LINUX.ORG.RU

А как комфортно работать со строками в современном C++?

 , ,


0

8

Привет, ЛОР.

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

К примеру, в библиотеке QtCore, входящей во фреймворк Qt, есть класс QString. Её часто ругают за изобретение велосипедов. Но именно благодаря этой «фабрике велосипедов» я могу написать, например, так:

QString s;
QStringList sl;
...
if (sl.contains(s, Qt::CaseInsensitive)) {
    ...
}

И оно мне проверит наличие строки в списке, причём регистронечувствительным (второй параметр) способом. И не только для латинских символов. То есть если в списке есть «Капибара», в строке подойдёт как «Капибара», так и «капибара». Ещё есть split(), join() и дофига полезного.

А как такое сделать без QtCore, на голом STL? В C++20 появился некий std::u8string, он мне поможет, например?

★★★★★
Ответ на: комментарий от alysnix

за иероглифы кстати пора карать. в 21 веке живем. пора это камменоугольные кракозябры отправить на свалку истории.

Население одного только Китая больше, чем население Европы (включая Россию) и Северной Америки вместе взятых. Смотри как бы они тебя не покарали.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

Население одного только Китая больше, чем население Европы (включая Россию) и Северной Америки вместе взятых. Смотри как бы они тебя не покарали.

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

Я вот читаю сейчас все этим правила, не так все страшно на самом деле. Все описано, спецификации есть, библиотеки есть для работы.

И у иероглифов тоже есть свои преимущества. Так как там слова состоят из морфем (в срднем двух на слово), то в китайком слово это в среднем 5-8 байт, а в русском около 12 байт в 2-3 раза компактнее выходит.

Вообще тут кириллица проигрывает одновременно и латинице и иероглифам, что забавно. В английском тоже среднее слово около 5 байт.

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 1)
Ответ на: комментарий от alysnix

Так в китайском морфемы вообще по 3-4 байта. Тут еще структура языка влияет. Я не к тому, что кириллица хуже - это вообще для меня побочно стало неприятным сюрпризом, а к тому, что иероглифы это не плохо. Есть свои преимущества в них.

Что интересно, в китайском еще и самые короткие в среднем предложения. Китайский самый компактный выходит, как внешне, так и байтово. Английский на втором месте чуууть чуть отставая от китайского. Русский сильно больше. Очень сильно. В среднем 30-60 байт китайский, 40-60 - английскйи, а русский 140-200.

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

ns_chat_log_line_q_p = {
	["лог_чат"] = {
		"  %  b 15 1I 1Z 2M 2l 34 3b 4F 4| 5- 5r 6M 6j 7H 7_ 83 8< 8T 8g 9A 9P 9z A* B9 BO Bg C8 C@ CZ Cn DF Db Dw EI Er FB FK F_ F] G) Gi #3 #k $H $v %H (0 (> (^ *I *j +A +M +y -/ -v /D /a /} ;R ;u <( <U <l =D >N @N @o H4 H) H` H[ II
LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 3)
Ответ на: комментарий от LightDiver

тут кириллица проигрывает одновременно и латинице и иероглифам, что забавно. В английском тоже среднее слово около 5 байт.

Вы сравниваете языки, а выводы делаете про алфавиты. Не надо так. Взяли бы польский и сравнили, что короче записывается: «Chrząszcz» или «хрущ».

ugoday ★★★★★
()
Ответ на: комментарий от alysnix

да они сами не рады своим иероглифам

Если убрать иероглифы, то окажется, что нет никакого китайского языка и китайцев, а есть разные народы, говорящие на разных языках. Так что есть иероглифы — есть Китай. Нет иероглифов → нет Китая. А ради такого дела можно и помучиться.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Про польский я ничего не знаю. Вполне допускаю, что на латинице русский будет еще хуже. Хотя, некоторые буквы вполне можно перевести. Да 90% букв кириллицы можно перевести на латиницу без потери смысла и только с пользой.

Но иероглифы тут еще выгоднее и интереснее, это самое интересное.

Но тут же еще эти все многочисленные суффиксы вступают в игру. Представь - слово из 1-2 иероглифов, без всяких суффиксов, просто морфемами. Это же круто.

LightDiver ★★★★★
()
Ответ на: комментарий от alysnix

В игре используется ютф-8, причем штатной работы с ютф-8 нет. В любом случае нужно кодировать, а если всеравно кодировать, проще кодировать к бинарный формат = «иероглифы». Но в этом случае нужен словарь, что хреново. С этой проблемой я еще не разобрался.

Если просто использовать ср1251 или просто транслитерацию, это люто бьет по процессору. Я еще ищу варианты. В идеале - или «легкое» кодирование без словаря, чтобы не перегружать ЦПУ или компактные варианты хранения словаря с быстрым доступом.

Причем без кодирования все в 3-4 раз хуже (медленнее), чем с кодированием - вот в чем парадокс. Потому что с кодированием мы реализуем кодирование, но используем стандартные оптимизированные инструменты, а без кодирования нужно использовать самописные медленные инструменты для работы с ютф-8. Еще и длиннее в несколько раз без кодирования.

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 3)

да, не хватает нормальных строк в си без плюсов, пока обходился что это массив какихто байтов, разбирать что это utf не приходится, регулярками, сложением, питон занимался, с этим кривым змеем обратная задача, говорю ему: это сырой набор байтов, а он валится (не при отладке, а в работе), вопя: не валидный utf-8.

s-warus ★★★★
()
Ответ на: комментарий от LightDiver

Про польский я ничего не знаю. Вполне допускаю, что на латинице русский будет еще хуже. Хотя, некоторые буквы вполне можно перевести. Да 90% букв кириллицы можно перевести на латиницу без потери смысла и только с пользой.

Кириллица хороша тем, что полнота звуков больше, в латинице их не хватает, вот и изгаляются как могут. Где-то лепят буквосочетания как в английском (Sh, Ch...), где-то диакритику (Ŝ, Ĉ...) как в чешском и прочих.

Dr64h ★★★
()
Ответ на: комментарий от Dr64h

Латиницу тоже давно стоило бы реформировать. Да и английский в целом. Там составных букв хватает вон. Та же ‘sh’ или ‘th’. Да в целом английский - бред наркомана по буквам и звукам.

LightDiver ★★★★★
()
Ответ на: комментарий от s-warus

Народ! А меня вот что интересует. Я про C.

Вот допустим из внешнего источника (с диска cvs, xlsx, ini, БД) извлекаю строки в utf8 (char*) и сразу конвертирую их в (wchar_t*).

Внутри программы работаю с wchar_t*, поэтому нет проблем с обработкой строк вида «Фирма Argus», где намешаны англ. с рус..

При выводе в консоль (на экран) вывожу с форматом ls

printf("%ls\n", wstr);

Если выводить как обычный char* (utf8), то слетает форматирование, потому что истинную длину строки для смешанных строк можно получить если исп. wchar_t* (ф-ция wcslen для wchar_t*).

А вот перед записью во внешие получатели (файлы и проч.), из wchar_t* конвертировать в char*.

Верно ли я делаю? Кто как работает со строками C на смеси русского и англ. языках?

PS Вначале программы всегда вызываю

setlocale(LC_ALL, "ru_RU.utf8");

PS2 Вообще тема отдельной ветки заслуживает

Gyros
()
Последнее исправление: Gyros (всего исправлений: 4)
Ответ на: комментарий от alysnix

хочется не думать, вдруг там умляут, или смайлик в имени файла, мне гемора с русскими папками, во всех отношениях достал:
переключать в консоли rus/lat, бороться с онли lat програмами.
А так кучка байт это имя файла, и копатся в нём это не благодарное дело, не дай бог выводить его на экран, пускай об этом терминал думает, или вызывающая питон прога на tk.

s-warus ★★★★
()
Ответ на: комментарий от s-warus

переключать в консоли rus/lat, бороться с онли lat програмами.

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

Dr64h ★★★
()
Последнее исправление: Dr64h (всего исправлений: 1)
Ответ на: комментарий от Gyros

поэтому нет проблем с обработкой строк вида «Фирма Argus», где намешаны англ. с рус..

Их и на UTF-8 нет, не знаю, кто вам сказал обратно.

А «длина строки» (а не количество codepoints!) в utf-8 получается через strlen. wcslen вам возвращает codepoints для сконвертированного wchar.

Я вас, наверное, удивлю, но wchar вам не гарантирует, что один wchar - одно знакоместо. Он гарантирует, что у вас один символ из Unicode таблицы может поместиться в один wchar. А (внезапно!) в unicode часть символов - это модификаторы символа, так что zalgo-text - это не один символ wchar, а такое же количество codepoints, что и в utf-8.

Более того, все эти извращения с wchar - костыль:

The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compiler should not use wchar_t for storing Unicode text.

PPP328 ★★★★★
()
Последнее исправление: PPP328 (всего исправлений: 3)
Ответ на: комментарий от LightDiver

Латиницу тоже давно стоило бы реформировать. Да и английский в целом.

Краткая история английского языка:

  1. Доисторическое время. Бродят дикие стада кельтов.
  2. I. Завоевание римлянами.
  3. IV. Римляне уходят.
  4. V. Зато приходят англы, саксы и пр. германцы.
  5. Набеги викингов. Постоянно набеги викингов.
  6. XI. Завоевание французами.
  7. Правление разных французских династий, затем шотландцев и немцев.
  8. XVII. Завоевание голландцами
  9. XVIII по настоящее время. Правят немцы.

Поэтому английский язык вот такой франко-германский суржик, с добавками от каждого из завоевателей (+ пытались облагородить латынью и греческим). Хотите его реформировать, что ж, путь известен. Сначала нужно пересечь Ла-Манш.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Немного резануло глаз - франки и есть германцы. Просто романизированные. Я знаю историю английского, у меня одно из хобби - языки. Правда в основном романские.

LightDiver ★★★★★
()
Ответ на: комментарий от LightDiver

без всяких суффиксов, просто морфемами. Это же круто.

ТЫ МОЧЬ ГОВОРИТЬ РУССКИЙ ЯЗЫК БЕЗ МОРФЕМ И ЗНАК ПРЕПИНАНИЕ ПРЯМО СЕЙЧАС Я НЕ ЗНАТЬ ЗАЧЕМ И ПОЧЕМУ КТОТО МОЧЬ ХОТЕТЬ ТАКОЙ ЯЗЫК ИСПОЛЬЗОВАТЬ ОДНАКО МАЛО ЛИ НА СВЕТЕ ИЗВРАЩЕНЕЦ

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Я не мочь, потому что что кириллица. Я хотеть компактно и удобно.

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

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 1)
Ответ на: комментарий от ugoday

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

LightDiver ★★★★★
()
Ответ на: комментарий от PPP328

А «длина строки» (а не количество codepoints!) в utf-8 получается через strlen. wcslen вам возвращает codepoints для сконвертированного wchar.

Но Gyros`у нужно именно число знакомест, как я понял. Вот этот способ годится?

https://en.cppreference.com/w/c/string/multibyte/mblen

// the number of characters in a multibyte string is the sum of mblen()'s
// note: the simpler approach is mbstowcs(NULL, str, sz)
size_t strlen_mb(const char* ptr)
{
    size_t result = 0;
    const char* end = ptr + strlen(ptr);
    mblen(NULL, 0); // reset the conversion state
    while(ptr < end) {
        int next = mblen(ptr, end - ptr);
        if (next == -1) {
           perror("strlen_mb");
           break;
        }
        ptr += next;
        ++result;
    }
    return result;
}
MirandaUser2
()
Ответ на: комментарий от Dr64h

Кириллица хороша тем, что полнота звуков больше, в латинице их не хватает, вот и изгаляются как могут.

Точно?

Где-то лепят буквосочетания как в английском (Sh, Ch…), где-то диакритику (Ŝ, Ĉ…)

ть, ль, сь, въ, съ.

Простая буква «е» то ли с йотом, то ли нет, в зависимости от того, где находится. Звук то ли «е», то ли «э» в заимствованных словах.

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

Он просто упустил, что полнота звуков для того или иного языка. Для русского, как и славянских в целом, лучше кириллица в этом плане.

Но и в кириллице и латинице полно своих косяков.

LightDiver ★★★★★
()
Ответ на: комментарий от PPP328

wchar вам не гарантирует, что один wchar - одно знакоместо. Он гарантирует, что у вас один символ из Unicode таблицы может поместиться в один wchar.

Он фактически не гарантирует, потому что на практике может быть 16-битным (на винде). А то, что он по стандарту может быть даже 8-битным, вообще не даёт возможности пользоваться им для хранения кодпоинтов юникода.

Относительно «знакомест» я уже высказывался ранее.

static_lab ★★★★★
()
Ответ на: комментарий от PPP328

я использовал термин знакоместо, а не character (приведенный код - пример с cppreference.com).

Например: в моем GUI/TUI приложении есть textbox (label и т.п.). Я хочу понять, поместится ли в него мультибайтовая utf8 строка (char*) при заданном моноширинном шрифте.

MirandaUser2
()
Ответ на: комментарий от MirandaUser2

Могут быть только платформозависимые решения

https://www.ibm.com/docs/en/i/7.5?topic=functions-wcswidth-determine-display-width-wide-character-string

Ширина и сдвиг текущей позиции («каретка» может быть и в середине текста, показанного в текстбоксе, если текст двунаправленный ) определяются не на нашей стороне.

vM ★★
()
Последнее исправление: vM (всего исправлений: 1)

Читая Qt документацию понятно, что QString здравая идея (на практике ). Но много неясностей для нубов - когда следует использовать QList, когда QQueue, когда QVector, для добавление этих строк или ещё чего подобного?

anonymous
()
Ответ на: комментарий от EXL

Интересно, как так получилось что за почти 40 лет разработки STL в C++ сосёт и требует от программиста написания вот этого вот:

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

anonymous
()
Ответ на: комментарий от basename

Требования к обратной совместимости. Ну и в С++ вообще всегда был упор на производительность, а не на удобство для разработчиков.

Это не в С++, а около него паслось всегда стадо упоротых по производительности, чаще всего за счет надежности. Это они делают проверку формата даты сравнением длины строки и потом сервер падает в проде если юзер поменял формат. Они же убирают остальные «ненужные проверки» и буквально любое изменение входных условий вызывает выстрелы там, где «вероятность крайне мала». Именно поэтому щас находят много CVE в коде, в котором девелоперы и не собирались практиковать «защитное программирование», «секурити бай дизайн» и т.д., а дрочили на «скорость исполнения» (при этом цикл разработки либо был затянут («компиляется!»(тм)), либо… сокращен засчет проверок и тестирования в условиях, о которых разработчики и не собирались думать).

anonymous
()
Ответ на: комментарий от MirandaUser2

Самостоятельно определить количество знакомест практически нереально, нужно учитывать слишком много факторов плюс сам шрифт тоже влияет. Если в шрифте нет поддержки конкретного композитного символа - то будет два знакоместа (например акут и а или две точки и e)

PPP328 ★★★★★
()
Последнее исправление: PPP328 (всего исправлений: 1)
Ответ на: комментарий от unC0Rr

ть, ль, сь, въ, съ.

Ну допустим мы уберём мягкий знак и заменим на отдельные буквы для каждого смягчённого звука. Тогда это будет примерно 47 букв а не 33. Добавлять 15 букв, учитывая что они отличаются лишь мягкостью звуков, которые уже и так присутствуют в алфавите не вижу особого смысла. Ещё есть вариант добавлять диакритику, но это не всегда так удобно.

Простая буква «е» то ли с йотом, то ли нет, в зависимости от того, где находится.

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

Dr64h ★★★
()

Мляяя.. А ты видел как это все делается в расте? Я вот сейчас колупаю, охренительный язык. Если не смотрел, глянь, вдруг тебе понравится.

Я вот чисто интереса ради эти ваши темы почитывал, хотя нихрена не понимал. А сейчас колупать взялся раст, а там все это на порядок проще и уже все реализовано. И работы со строками и выравнивания и прочее. Все с чем вы мучались.

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 1)
Ответ на: комментарий от LightDiver

Верю.

Вот только приделать к плюсам нормальную библиотеку работы со строками можно (и пример такой библиотеки я приводил в ОП, жаль, что сторонняя, но с этим можно примириться). А вот приделать к расту полноценное наследование, похоже, никто не собирается, и судя по соседней теме, поклонники языка считают это фичей.

Как в том анекдоте – «Я-то завтра протрезвею…»

hobbit ★★★★★
() автор топика
Ответ на: комментарий от hobbit

А зачем тебе наследование? Чем тебе композиция не нравится?

Я вон в луа по сути только с композицией и работаю, там других вариантов нету. Одно и то же по сути.

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 1)
Ответ на: комментарий от LightDiver

А зачем тебе наследование? Чем тебе композиция не нравится?

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

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

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

alysnix ★★★
()
Ответ на: комментарий от LightDiver

у наследования в ООП два назначения: главное и полезное - обеспечение типизированного полиморфизма, второе - наследование реализации, оно же жёсткий антипаттерн(особенно данных), применяют для экономии копипасты, попутно ломая и намертво связывая архитектуру. Ещё общий косяк оопешных иерархий, однобокая завязка на типы произведения, а в общем случае предметная область которая ложится только на деревянную иерархию - исключительная редкость. В расте более общий и гибкий подход для декомпозиции - алгебраические типы (комбинируют произведения и суммы типов) + трейты(классы типов, интерфейсы) + дженерики(шаблоны ). Как-то так

zurg
()
Последнее исправление: zurg (всего исправлений: 1)