LINUX.ORG.RU

Хорошие библиотеки для обработки строк на C++

 ,


1

4

А есть ли для C++ хорошие библиотеки для обработки строк в функциональном стиле?

Чтобы можно было, например, решить задачу вида «разбить строку по символу переноса строки, удалить завершающие пробелы, отфильтровать непустые строки, вывести» как-то так:

std::string text = ...;
text.split('\n')
    .map([](auto s) { return s.trim(); })
    .filter([](auto s) { return !s.empty(); })
    .for_each([](auto s) { std::cout << s << std::endl; });

Разумеется, это всё ещё должно работать на базе string_view или аналога из библиотеки, чтобы не было лишних копирований и аллокаций. И без создания промежуточных контейнеров.

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

Если прям нужно работать с UTF, то для этого есть отдельные продвинутые либы, вот описание к ним:

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

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

Ну в большинстве случаев строки на стёке особо никто не хочет использовать. Если можно использовать аллокатор, то использовать строки на стёке попросту опасно и сложнее. Нужно следить за переполнением как стёка, так и выделяемых буферов. С кучей всё куда проще. Возможно, если бы C++ умел доказывать, что какие-то строки при любых данных влезут в выделенные буферы, а этот буфер влезет в стёк, то это было бы удобно. Но C++ так не умеет и не научится. Ада, насколько я понял, тоже не умеет.

А там, где важно выделять строки именно на стёке можно вполне явно пользоваться заранее выделенными буферами, string_view и fmt::format/std::format (ну или сишные аналоги, сам я, если что, fmt::format в embedded не пробовал). По моему опыту просто сложение строк бывает нужно редко, в 90% случаев нужно именно форматирование по шаблону. Всё остальное (кроме сложения) есть в string_view.

Ну или вообще можно использовать pmr, как описано выше, и будет абсолютно полноценный string на стёке.

В общем если подвести итог, то в C++ можно делать со строками стандартными средствами всё тоже самое, что и в аде, практически тем же способом, за редкими исключениями.

Это всё мелочи, и на деле нормальная поддержка utf-8 и производительность в разы важнее сколь-угодно удобной конкатенации строк на стёке.

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

Что мешает сделать нечто подобное в плюсах?

Тут работать надо и отлаживать. Perl вон сколько работу с юникодом отлаживал и продолжает отлаживать… А те, кто сегодня развивают С++, они хотят в метапрограммирование, к сожалению.

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

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

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

UTF8: А что есть разделители между словами? А с какой стороны запятая в арабском языке? А какой символ у переноса строки? А какие символы это цифры? А какие буквы заглавные? И пр.пр.пр. Если учесть, что UTF8 все еще получает новые символы, то это превращается в адЪ. Потому если возможно ограничиться ASCII, то им и ограничиваются…

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

Это всё мелочи, и на деле нормальная поддержка utf-8 и производительность в разы важнее сколь-угодно удобной конкатенации строк на стёке.

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

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

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

Символов или глифов? (:

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

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

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

Да могут они всё, просто надо лямбду принимать как шаблонный аргумент, а не обёрнутую в std::function. Тогда всё заинлайнится. Надо смотреть как реализована конкретная библиотека.

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

на эмбеде документы не обрабатывают

Эмбед у плюсов всё-таки не самая приоритетная ниша, так что глобально utf куда как важнее конкатенации строк на стёке. Ну и как я писал выше, со строками в эмбеде у плюсов проблем нет - бери да пользуйся.

в области железок, utf 8 и прочие utf не столь актуальны

Ну тут смотря что за железки. Современные технологии вполне позволяют встраивать не микроконтроллеры, а полноценные процы, где крутится полноценный линукс с полноценной utf-8 локалью, переводами, очень часто веб-интерфейсом. Там utf очень даже нужен.

А если речь идёт всё-таки про микроконтроллер, то там и обработка строк задача не особо частая.

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

Где-то читал, что с использованием в сорцах UTF математики на Аде стали использовать математические символы для констант и формул.

π : constant Float := 3,14159
Не знаю на сколько это удобно, но на первый взгляд интересно.

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

Ну то есть, если код лямбды в другом модуле, то упс и ах. Печалька, чо.

С lto это не будет проблемой, по идее. Lto код всех модулей вполне видит, и если посчитает нужным - заинлайнит.

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

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

Это очень плохо. Текст кода должен быть на ASCII, единственное исключение это комментарии, в крайнем случае, иногда можно встроенные строковые константы еще делать. Отступление от этого негласного правила сулит кучу неожиданных проблем.

// про национальные языки типа 1С я не говорю, там ситуация иная.

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

Например? Что такого в использовании греческих символов для определения констант?

Ну на вскидку, как компилятор/транслятор будет воспринимать такие символы, будет ли он считать их разделителями между словами, будет ли он корректно выводить сообщения об ошибках и пр. И будет ли такой код работать так же на других компьютерах, в винде вроде все еще не UTF8 основная кодировка…

Кучу лет назад я пробовал написать на VBA программу с русским языков, и на секундочку, это еще было CP1251, отлаженная, короткая и ясная кодировка. Я поимел столько проблем со сдачей этого кода…

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

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

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

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

Тогда зачем нам вообще C++, если всё можно реализовать на Си?

С++ предоставляет другой уровень абстракций. С++ это мета-С, чем дальше тем больше.

Как устроен range в Аде

Конечно видел. Обычная паскалятина. Бесполезный синтаксический сахар для невыразительного языка.

Про wchar ты видимо тоже не вкурсе.

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

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

если код лямбды в другом модуле, то упс и ах. Печалька, чо.

Если код лямбды в другом крестовом модуле, то и в крестах все будет инлайниться. Объектники модулями считать можно только по причине столкновения терминологии.

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

С++ предоставляет другой уровень абстракций. С++ это мета-С, чем дальше тем больше.

И что... Си и C++, это два разных языка, просто плюсы продолжают поддерживать какую-никакую совместимость с Си.

Конечно видел. Обычная паскалятина. Бесполезный синтаксический сахар для невыразительного языка.

А как же ссылки, зачем они, это же по твоему бесполезный сахарный синтаксис, давай ещё на goto циклы кодить.

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

Про Юникод не совсем я начал, ну да ладно.

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

Умеют. Если персонаж под оптимизацией понимает инлайн, то иначе как бредом его сообщение назвать не могу.

Тогда обоснуй зачем нужны инлайны.

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

И что…

И то, что оба языка являются состоятельными, что не мешает им различаться. Поэтому выкинуть какой-то один можно, но смысла не имеет.

А как же ссылки, зачем они, это же по твоему бесполезный сахарный синтаксис

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

Не говоря уже про rvalue-ссылки и forwarding-ссылки.

range в Аде ничего не добавляет в язык и легко реализуется на коленке – в отличие от ссылок.

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

Видимо у тебя розовые фантазии относительно Юникода. Он ужасен, его убили попыткой всунуть туда всё на свете, когда надо было ограничиться лишь алфавитными системами с одним направлением письма. Всех остальных ретроградов, любителей наскальной живописи отправить в другую кодировку, когда выздоровят, то добро пожаловать в Юникод с алфавитом в руках. А пока есть нормальный ASCII и какое-то дерьмо над 127, я слабо верю, что он имеют шансы на серьзную и полную поддержку в софте, он нежизнеспособен.

Не то чтобы я не осилил Юникод, я даже запилил свой UString, в процессе я стал его ненавидеть. Софт с полной поддержкой можно пересчитать по пальцам.

Только к встроенным плюсовым типам это не имеет никакого отношения, нет никакого смысла что-то встраивать.

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

Видимо у тебя розовые фантазии относительно Юникода.

Я и не предлагал вводить Юникод, просто сверху спрашивали как обстоят дела с ним в Аде.

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

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

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

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

С++ компилятор обязан работать с unicode: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1949r7.html

https://gcc.godbolt.org/z/q8shq9Exh

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

Арабы вот пишут справа налево, а цифры в числах – слева направо.

Не знал. Но может для них «от меньшего к большему» более естественно? Вот только к непостоянству направления имхо это мало имеет отношения: скорее ортогональный атрибут.

PS. А что, направление письма как-то влияет на Юникодное представление? Я бы ожидал что это проблема renderer’а, нет?

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

Нет, это потому что арабские цифры не арабские, а индийские. А к арабам они пришли путем перевода математического труда Брахмагупте «неким» Аль-Хорезми, который скорее всего то и арабом не являлся…

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

Поэтому написание библиотек работы со строками это больше задача филологов, чем программистов. Ну и соотв. для каждого языка должна быть своя библиотека, т.е. для каждого национального диапазона в UTF8. Что приводит к печальной и разумной мысли об использовании ASCII, и интерпретации всего остального, как последовательности байтов (или абстрактных многобайтных char’ов)

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

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

Подождите, подождите. Вы хотите сказать что добавление слова в конец фразы на арабском приводит к условному «push_front()»?

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

Умеют. Если персонаж под оптимизацией понимает инлайн, то иначе как бредом его сообщение назвать не могу.

Инлайн – это в общем-то основная штука, которая нужна, чтобы вот это вот .map([](auto s) { return s.trim(); }) превратилось в обычный цикл, который потом можно развернуть.

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

Строк как типов данных не существует. Это просто случайный набор байтов, где размер логического элемента колеблется от кодировки к кодировке и случая к случаю. Если взять конкретную кодировку то да можно сделать тип строка с конкретной кодировкой, и по хорошему получится что для каждой кодировке нужен будет свой тип строк свои функции обработчики кодировок много и указывать их нужно явно, автоматически распознать невозможно. Поэтому строк как типов данных просто не существует. Да в языках есть всякого рода упрощалки жизни которые называют себя строками, но это лишь реализации наиболее популярного ибо кодировка там прибита гвоздями. Это не универсально. Вот если вдруг бабах во всём мире вымрут все кодировки кроме UNICODE и единственным форматом представления станет UTF-8. Попутно отвалятся всякие дебилизмы вроде составных символов. И всё станет однозначно, вот тогда да. Тогда у нас появятся фиксированные по организации внутренней структуры данные, предсказуемые, однозначные, точные. Тогда можно будет на уровне любого языка реализовать работу с такими данными. А сейчас, сейчас тебе в языке со «строками» попадётся файл 15 летней давности и программа со строками ничего с ним сделать не может ибо в душе не чает чего там за месиво байт вместо ЮТФвусемь. :D

Так и живём, просто надеемся что нам попадётся наиболее распространённое ANSI, UTF8 или не паримся и юзаем то что даёт сам язык UTF-16, а потом фигак то кто надеялся на UTF8 получает от тебя файл в UTF16 и приехали снова в туже лужу что и дцать лет назад, перекодировать надо. А ещё сурогаты уууууууууууооооооооооооооо.

Йя так вижу :D

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

Строк как типов данных не существует. Это просто случайный набор байтов

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

Dr64h ★★★
()