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, он мне поможет, например?

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

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

Методы - разнообразные способы работы с данными. Запись в разные типы таблиц, чтения из разных типов. Все возможные и нужные мне варианты.

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

Но из за особенности «классов» в луа - это ничем не отличается от композиции. Я точно так же могу в конструкторе создать экземпляр первого класса и работать с ним, в принципе.

Второй вариант, до которого я пока додумался: делаем в конструкторе self.__index = self и можем наследовать уже не сами классы, а экземпляры классов. Причем в любой момент и правильными методами работать с данными между наследованными экземплярами.

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

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

но это охрененно - изучаю раст и он прекрасен, как по мне. Это же шедевр в синтаксисе, возможностях, он просто красив в стиле.

После луа-то? Даже не сомневаюсь. Это как я на 3 курсе упоролся, написав на бейсике (нет, не на VBA, его тогда не было, а на классическом бейсике, где подпрограмму можно было сделать только через GOSUB) программу в 2000 строк. Я её написал, но понял, что это предел. После чего я перешёл на паскаль, и это был охрененный шедевр. К сожалению, дома компа, тянущего паскаль, не было, только в институте.

А луа она конечно, хороша для скриптоты.

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

Ну вот когда других вариантов нет, привыкаешь. А есть языки, где можно выбирать. И вот тут возникает вопрос, «зачем они бьют программиста по рукам, можно было дать выбор».

Кстати, синтаксис объявления функций в расте больше на паскаль похож, чем на C/C++/Java. Явно присутствует ключевое слово fn. И это действительно логично.

А недостаток раста, на мой взгляд… такой же, как у паскаля. Его пилит одна команда. В комитете по C++ сидит много игроков, все изменения очень придирчиво обсуждаются, потом выпускается стандарт. @Croco может сколько угодно ругать «комитетные» языки, но они дают гарантию высокой живучести языка. И всегда на выбор есть несколько компиляторов, и свободных, и проприетарных… В общем, плюсы могут жить ещё лет 20, даже если кто-то их будет планомерно экскаватором закапывать.

А rust — это vendor lock. Не такой, как винда или фотошоп, конечно. Но они могут ещё несколько лет полировать своё детище, вынуждать авторов прикладного софта бежать за ними, а потом им всё это надоест, они разбегутся, и всё. Кстати, ты ещё и не имеешь права сделать свой компилятор раста, они это имя защищают. Так что может, будет ещё хуже, чем с fpc сейчас. Хотя если на этот vendor lock завяжут ядро линукса, к чему сейчас потихоньку идёт, может, кто-то будет выкручиваться и некромантить язык с синтаксисом, как у раста, но не раст. Линуксу просто так помереть не дадут.

С паскалем примерно аналогично (хотя сторонние компиляторы там никто выпускать, кажется, не запрещает). Там долгое время единственным игроком был Борланд, навносили много спорного, хотя и хорошего тоже было много. Сейчас вот всё держится на команде fpc. Горстке энтузиастов, пишущих на этом, хватает, но не более того.

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

Скорее, стоит, чем нет.

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

Но если ни на сишке, ни на плюсах ты не писал, то почему бы и нет. Более того, если нет возможности сразу начать плюсы с C++20, где появились модули (они ещё и реализованы не везде, вроде как), то тут раст выглядит явно красивее. А если потребуется вкатиться в какой-то проект, где он уже используется, то тут без вариантов.

Для человека, серьёзно занимающегося программированием, владеть несколькими ЯПами одного уровня – это нормально. Понятно, что один из них будет освоен намного лучше, поскольку практика решает, но тем не менее.

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

Если только начинаете заигрывать с низкоуровневым программированием, то начните с Си. Этот язык вечен, ибо основа области, плюс это связующий язык между другими языками. В будущем на нем можно не писать, но знать нужно обязательно(даже дизасемблер выдает псевдокод на Си). C этим языком у вас даже не возникнет вопроса уровня «А вот если через 5\10\15 лет про него все забудут». А после Сишки можно что угодно учить для развлечения.

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

Но если ни на сишке, ни на плюсах ты не писал, то почему бы и нет.

По-моему наоборот.

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

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

Я обязательно еще изучу более углубленно и си и с++ после раста. Спасибо за советы. И питон. А там видно будет.

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

LightDiver ★★★★★
()

А во многих случаях надо работать со строками именно как со строками текста.

Только у тебя нету в примере нормальной работы с текстом, вот пример:

#include <QString>
#include <QLocale>
#include <QDebug>
#include <iostream>
#include <wchar.h>
#include <locale.h>

int main() {
    setlocale(LC_ALL, "tr_TR.UTF-8");
    QLocale::setDefault(QLocale("tr_TR"));

    std::cout
        << (QString("ı").contains("I", Qt::CaseInsensitive) ? "Qt <3" : "Qt sucks")
        << "\n";

    std::cout
        << (towupper(L'ı') ==  L'I' ? "libc <3" : "libc sucks")
        << "\n";
}
Qt sucks
libc <3
Ну и работа с текстом! Надеюсь никто так не работает с человеческим текстом.

И не только для латинских символов.

Как видим, это не совсем правда.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 6)
Ответ на: комментарий от MOPKOBKA
QString("ı")

Вот здесь ошибка. Так можно писать только ASCII-символы.

Всё остальное, если оно уж появляется в исходниках, надо обрамлять в QString::fromUtf8() или в trUtf8(). А обычно рекомендуют всю нелатиницу вообще выносить в файлы переводов.

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

Тут нету ошибки, с твоими функциями будет точно так же.

Вот более простой пример...

#include <QString>
#include <QLocale>
#include <QDebug>
#include <iostream>
#include <wchar.h>
#include <locale.h>

int main() {
    setlocale(LC_ALL, "tr_TR.UTF-8");
    QLocale::setDefault(QLocale("tr_TR"));

    std::cout
        << (QChar(L'i').toUpper().unicode() == L'İ' ? "Qt <3" : "Qt sucks")
        << "\n";

    std::cout
        << (towupper(L'i') == L'İ' ? "libc <3" : "libc sucks")
        << "\n";
}

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

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

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

Я даже запускать не стал твой специально поломанный пример.

Понятно, то есть ты просто любишь врать, из за тебя я сделал неверный вывод что в Qt меняется поведение версия от версии. Не пиши свою чушь тут больше пожалуйста, очисти тред.

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

Чушь тут пишешь только ты.

#include <QString>
#include <QLocale>
#include <QDebug>
#include <iostream>
#include <wchar.h>
#include <locale.h>

int main( int argc, char** argv )
{
	setlocale(LC_ALL, "tr_TR.UTF-8");
	QLocale::setDefault(QLocale("tr_TR"));

	std::cerr
		<< (QChar(L'ı').toUpper() == QChar(L'I') ? "Qt <3" : "Qt sucks")
		<< "\n";

	std::cerr
		<< (towupper(L'ı') == L'I' ? "libc <3" : "libc sucks")
		<< "\n";
}
anonymous
()
Ответ на: комментарий от anonymous

Все хорошо с головой?

#include <QString>
#include <QLocale>
#include <QDebug>
#include <iostream>
#include <wchar.h>
#include <locale.h>

int main( int argc, char** argv )
{
	setlocale(LC_ALL, "tr_TR.UTF-8");
	QLocale::setDefault(QLocale("tr_TR"));

	std::cerr
		<< (QChar(L'i').toUpper() == QChar(L'İ') ? "Qt <3" : "Qt sucks")
		<< "\n";

	std::cerr
		<< (towupper(L'i') == L'İ' ? "libc <3" : "libc sucks")
		<< "\n";
}
Qt sucks
libc <3

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

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

Оригинальный код hobbit не работает, и мне было интересно показать где он не работает. Все! А хороший ли API у Qt, это ты уже можешь выяснять без меня.

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

Забавно, видимо и вправду зависит от версии, в документации трудно что то найти... Но такое точно не должно правильно (ожидаемо) работать в Qt5/Qt6:

#include <QString>
#include <QLocale>
#include <QDebug>
#include <iostream>
#include <wchar.h>
#include <locale.h>

int main( int argc, char** argv )
{
	setlocale(LC_ALL, "tr_TR.UTF-8");
	QLocale::setDefault(QLocale("tr_TR"));

	std::cout << QString("i").toUpper().toStdString() << "\n"; 
}

Как и код hobbit, можно попробовать мой пример оригинальный.

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

Наверное скопировал пример анонимуса выше, там другие буквы, и Qt дает идентичные результаты с libc. Можно остановится на том что локали странные и запутанные... Возможно именно поэтому в С++ нету работы с текстом из коробки.

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

Кстати, синтаксис объявления функций в расте больше на паскаль похож, чем на C/C++/Java.

Он прямо взят из OCaml, только убрали карринг и сделали сиобразные скобки.

Кстати, ты ещё и не имеешь права сделать свой компилятор раста, они это имя защищают.

Ты имеешь право сделать свой компилятор раста, но не имеешь права называть его растом (без их разрешения), точно также как free pascal а не free delphi. Это ничем не отличается от того что мозилла (откуда и это яблочко прикатилось) не разрешает чужие сборки своего браузера называть firefox, делать и выпускать под другими названиями никакого запрета нет.

С паскалем примерно аналогично (хотя сторонние компиляторы там никто выпускать, кажется, не запрещает). Там долгое время единственным игроком был Борланд, навносили много спорного, хотя и хорошего тоже было много. Сейчас вот всё держится на команде fpc. Горстке энтузиастов, пишущих на этом, хватает, но не более того.

Так все уже никакого борланда для раста нет, мозилла отказалась теперь все в руках энтузиастов (Rust Foundation) отличие от fpc только в том что в числе «энтузиастов» много богатых корпораций.

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

теперь все в руках энтузиастов (Rust Foundation) отличие от fpc только в том что в числе «энтузиастов» много богатых корпораций.

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

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

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

Куча языков и без комитета прекрасно живут и развиваются, тот же питон как пример.

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

Наверное скопировал пример анонимуса выше, там другие буквы, и Qt дает идентичные результаты с libc.

Вот этот пример анонимуса?

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

Но там буквы как раз те, что надо, для демонстрации того, что QT при сравнении строк не учитывает локаль. Или QChar в этом плане отличается от QString?

Вопрос ещё в том, насколько корректен тест libc:

towupper(L'ı') ==  L'I'

Ведь при преобразовании L’ı’ в uppercase нет неоднозначности, в отличие от преобразования ‘I’ в lowercase.

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

помощь от корпораций линуксу примерно того же характера, как помощь корпораций голодающим детям африки.

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

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

точно также как free pascal а не free delphi

Ну так я и сравниваю именно с нынешним fpc, а не с огороженной Delphi. С ней (при всех её заслугах в прошлом) всё ясно.

Это ничем не отличается от того что мозилла (откуда и это яблочко прикатилось) не разрешает чужие сборки своего браузера называть firefox, делать и выпускать под другими названиями никакого запрета нет.

Называется ли браузер Firefox или, к примеру, IceWeasel – большого значения для его ЦА не имеет. А вот если окажется, что ядро самой популярной открытой ОС в значительной части написано на языке, который нельзя называть – это уже намного интереснее и способно породить большую путаницу. Совсем это линукс не убьёт, но нервы разработчикам способно попортить как следует.

Хотя вот хозяева BitKeeper тоже полагали, что как следует посадили линукс-сообщество на свой ржавый (гы-гы) гвоздь, а Линус, как только они начали борзеть, взял и написал Git. Это внушает оптимизм, да. Но VCS – она немножко сбоку от исходников, сменить VCS всё-таки сильно проще, чем сменить компилятор на частично совместимый.

Куча языков и без комитета прекрасно живут и развиваются, тот же питон как пример.

На питоне ничего особо критичного ещё не написано. А люди, которые пишут подёнщину, с его ломками и особенностями помирятся, они за это в большинстве своём деньги получают. И та же openCV сама написана на плюсах, соответственно, питоноподелия на нё основе тоже переписать можно на другой ЯП, если что. :))) Вот, питоний yum перестал редхат устраивать, его переписали на Си и превратили в dnf. :)))

Я немножко утрирую, да. Но питон мне в любом случае не особо жалко, это утилитарный язык для скриптоты, со своей задачей справляется хорошо. Был бейсик, был перл, сейчас питон, будет ещё что-нибудь. Кто на него закладывается для более масштабных задач – ССЗБ. А вот к языку, используемому для системного программирования (да и для крупных прикладных проектов тоже), требования уже немножко совсем абсолютно другие. Не в последнюю очередь – к гарантиям его живучести и развития.

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

а по итогу: Ruby open-uri (скриптовый язык) показал наименьший пинг в сетевых тестах.. н-да.. если не для жалования, то понятно, что брать..

Если есть офер на Питон, почему бы не выучить, а так - ООП оно жеж стандартно/шаблонное, хыть чо изучай)

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

Ну не знаю, порою мне кажется, что изучение множества языков есть разновидность «клипового мышления». Хело-ворд, хело-ворд и всё надоело. Помимо языков есть куча всего ещё общего: солиды разные, построение сверху-вниз и пр…

К старости будет проще - в компьютерном мире всё упрощается (если делать ретроспективный анализ от 197х) :))))

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

Клиповость то клиповость, но если в луа и питоне объяснение типов переменных займет десяток фраз и все понятно, то в раст это 50-70 уроков и все только ветвится и размножается. Хотя общую суть я смутно понимал и даже кое что писал иногда на си. Правда оно не всегда работало. Теперь понимаю почему.

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

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

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

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

Помимо языков есть куча всего ещё общего: солиды разные, построение сверху-вниз и пр…

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

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

Но иногда у меня возникает ощущение, что я скорее помру от старости, чем изучу все из своих хотелок.

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

Легко понять указатели в С если знаешь что можно сделать

mov rax, [var] 
mov rcx, [rax]

Легче понять лямбды если знаешь что можно передать указатель на функцию и void *user аргумент.

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

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

хорошо, но это скорее претензия к коду ТС, а не к QT.

Т.к. QString::localeAwareCompare всё-таки есть.

А вот то, что оно работает через глобальный QLocale::setDefault, делает localeAwareCompare бесполезным в MT приложениях.

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

но ведь и в твоем примере libc проверяется именно таким способом:

(towupper(L'ı') ==  L'I' ? "libc <3" : "libc sucks")
MirandaUser2
()
  1. В ZenLib от авторов MediaInfo есть Ztring – наследник от std::basic_string со многими полезными функциями:
#include <stdio.h>
#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include "ZenLib/Conf.h"
#include "ZenLib/Ztring.h"
#include "ZenLib/ZtringListList.h"
#include "ZenLib/MemoryDebug.h"

using namespace ZenLib;

int main(char /*argc*/, char ** /*argv*/)
{
    //Ztring and Unicode
    //-How To Use
    Ztring Z1, Z2;
    Z1+=Z2.From_Unicode(L"Unicode - \xE0\x01FC\r\n");
    Z1+=Z2.From_Local("No Unicode - abc\r\n");
    Z1+=Z2.From_Number(0x7FFFFFFFFFFFFFFFULL);
    //Displaying
    #if defined(_UNICODE)
        wprintf (L"%s\r\n", Z1.c_str());
    #else
        printf ("%s\r\n", Z1.c_str());
    #endif

    //ZtringLisList
    ZtringListList ZLL;
    ZLL=L"11;12;13\r\n21;22;23\r\n31;32;33";
    wprintf (L"\r\nZtringListList\r\n%s\r\n", ZLL.Read().c_str());
    wprintf (L"%s\r\n", ZLL.Read(1).c_str());
    wprintf (L"%s\r\n", ZLL.Read(1, 1).c_str());

    //Debug Mode
    char* MemoryLeakDetectionTest=new char[50]; //Search for a file Debug_MemoryLeak.txt

    system("PAUSE");
}
  1. Есть совместимая по API с std::string https://github.com/DuffsDevice/tinyutf8.
  2. Много полезных функций можно надёргать из гигантского хидера https://github.com/ArashPartow/strtk.
dataman ★★★★★
()
Ответ на: комментарий от MirandaUser2

хорошо, но это скорее претензия к коду ТС, а не к QT.

Да, хотя у Qt на мой взгляд запутанная документация и API. Может есть руководство где работа с текстом более подробно описывается?

Т.к. QString::localeAwareCompare всё-таки есть.

И для contains можно закостылить, просто все «удобство» показанное в примере улетучивается. И может привести к странным проблемам.

А вот то, что оно работает через глобальный QLocale::setDefault, делает localeAwareCompare бесполезным в MT приложениях.

У Qt есть методы где можно напрямую передавать локаль.

но ведь и в твоем примере libc проверяется именно таким способом:

Ты уже на другой пример переключился, там код libc нужен что бы показать, что contains в Qt должен срабатывать.

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