На этом уроке мы будем работать со строками. Для этого в Qt5 реализован класс QString, который является очень мощным классом с большим количеством полезных методов.
Строки
Класс QString предоставляет Unicode-строку, которая сохраняет обычную строку в качестве 16-битных значений типа QChar, где каждый QChar соответствует одному символу формата Unicode 4.0. В отличие от строк во многих других языках программирования, QString можно изменять.
Примечание: Все примеры данного урока выполнены в формате консольного приложения. Поэтому, если вы откроете файл проекта, то сможете увидеть строку QT -= gui
, которая отключает модуль Qt GUI, отвечающий за графический интерфейс пользователя.
В нашем первом примере мы попробуем использовать несколько базовых методов класса QString. В этом нам поможет класс QTextStream, который предоставляет удобный интерфейс для чтения и записи текстовых данных:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <QTextStream> // подключаем необходимый заголовочный файл int main() { QTextStream out(stdout); // Создаем строку типа QString QString a = "love"; // Добавляем текст в конец строки a.append(" chess"); // Добавляем текст в начало строки a.prepend("I "); // Выводим строку out << a << endl; // Выводим количество символов строки out << "The a string has " << a.count() << " characters" << endl; // Выводим всю строку в верхнем регистре out << a.toUpper() << endl; // Выводим всю строку в нижнем регистре out << a.toLower() << endl; return 0; } |
Результат выполнения программы:
Обратите внимание, методы a.toUpper()
и a.toLower()
не модифицируют исходную строку, а работают с её копией.
А в следующей строке мы создаем объект (вы можете назвать его как хотите) out
класса QTextStream, чтобы связать его со стандартным выводом (stdout
) и иметь возможность использовать функционал класса QTextStream — выполнять вывод на экран:
1 |
QTextStream out(stdout); |
Инициализация строк
Класс QString позволяет инициализировать строки разными способами. Ниже представлен пример с 5-ю различными вариантами инициализации:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <QTextStream> int main() { QTextStream out(stdout); // Инициализация №1: Традиционный вариант QString str1 = "The night train"; out << str1 << endl; // Инициализация №2: Объектный способ QString str2("A yellow rose"); out << str2 << endl; // Инициализация №3 std::string s1 = "A blue sky"; QString str3 = s1.c_str(); out << str3 << endl; // Инициализация №4 std::string s2 = "A thick fog"; QString str4 = QString::fromLatin1(s2.data(), s2.size()); out << str4 << endl; // Инициализация №5 char s3[] = "A deep forest"; QString str5(s3); out << str5 << endl; return 0; } |
Результат выполнения программы:
Инициализация №3: Инициализация строки с помощью средств Cтандартной библиотеки C++. Метод c_str() генерирует строку C-style. Данный массив символов, который является классическим способом представления строк в языке Си, может быть присвоен объекту класса QString:
1 2 |
std::string s1 = "A blue sky"; QString str3 = s1.c_str(); |
Инициализация №4: Мы конвертируем стандартную С++ строку в объект класса QString, используя метод fromLatin1(). Данный метод принимает указатель на массив символов, возвращаемый методом s2.data()
. Второй параметр — это размер строки:
1 2 |
std::string s2 = "A thick fog"; QString str4 = QString::fromLatin1(s2.data(), s2.size()); |
Инициализация №5: А это строка в языке Cи, которая является массивом символов. Один из конструкторов класса QString может принимать массив символов в качестве параметра:
1 2 |
char s3[] = "A deep forest"; QString str5(s3); |
Доступ к элементам строки
Объект класса QString представляет собой последовательность QChar-«символов» (я специально взял в кавычки слово «символы»). Доступ к элементам строки можно получить c помощью оператора индексации []
или метода at(). В следующем примере мы будем выводить отдельные символы строки, которая является объектом класса QString:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <QTextStream> int main() { QTextStream out(stdout); // Исходная строка QString a = "Eagle"; // Выводим первый символ строки out << a[0] << endl; // Выводим пятый символ строки out << a[4] << endl; // Выводим первый символ строки с помощью метода at() out << a.at(0) << endl; return 0; } |
Результат выполнения программы:
Примечание: Убедитесь, что при использовании метода at() ваш индекс не выходит за границы массива.
Длина строк
Есть 3 метода, которые позволяют получить информацию о длине строки:
size();
count();
length().
Все они делают одно и то же — возвращают количество символов в строке. В следующем примере мы выводим длину четырех строк:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <QTextStream> int main() { QTextStream out(stdout); // Обычная строка QString s1 = "Eagle"; // Здесь у нас символ новой строки QString s2 = "Eagle\n"; // Здесь у нас пробел в конце строки QString s3 = "Eagle "; // А это вообще кириллица QString s4 = "орел"; out << s1.length() << endl; out << s2.length() << endl; out << s3.length() << endl; out << s4.length() << endl; return 0; } |
Результат выполнения программы:
Построение строк
Динамическое построение строк позволяет нам заменять определенные управляющие символы нужными нам значениями. Для этого используется метод arg(). Место, в которое нужно вставить значение, помечается специальным маркером — символом %
. Число, следующее за символом %
, является номером аргумента. Аргументов может быть несколько. Метод arg() может принимать следующие типы данных: int, long, char, QChars и др.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include <QTextStream> int main() { QTextStream out(stdout); // Используем маркер %1 для вставки значения QString s1 = "There are %1 white roses"; // Наш маркер будет заменяться этим целочисленным значением int n = 12; // Выполняем операцию вставки значения out << s1.arg(n) << endl; // Используем маркер %1 для вставки значения QString s2 = "The tree is %1 m high"; // Наш маркер будет заменяться этим значением типа с плавающей точкой double h = 5.65; // Выполняем операцию вставки значения out << s2.arg(h) << endl; // Используем 2 маркера для вставки 2 значений QString s3 = "We have %1 lemons and %2 oranges"; // Наши маркеры будут заменяться следующими значениями int ln = 12; int on = 4; // Выполняем операцию вставки out << s3.arg(ln).arg(on) << endl; return 0; } |
Результат выполнения программы:
Подстроки
При работе со строками вам может понадобиться выделить подстроку из исходной строки. Справиться с данной задачей помогут методы left(), right() и mid():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <QTextStream> int main() { QTextStream out(stdout); // Исходная строка QString str = "The night train"; // Возвращаем подстроку длиной 5 символов, начиная с правого края строки str out << str.right(5) << endl; // Возвращаем подстроку длиной 9 символов, начиная с левого края строки str out << str.left(9) << endl; // Возвращаем подстроку длиной 5 символов, начиная с 4-ого символа строки str out << str.mid(4, 5) << endl; QString str2("The big apple"); QStringRef sub(&str2, 0, 7); out << sub.toString() << endl; return 0; } |
Результат выполнения программы:
Класс QStringRef является версией «только для чтения» класса QString. Первым параметром мы указываем исходную строку, вторым — начальную позицию, третьим — длину подстроки:
1 2 |
QString str2("The big apple"); QStringRef sub(&str2, 0, 7); |
Циклы и строки
Объекты класса QString состоят из элементов типа QChar. При этом мы можем использовать циклы для доступа к каждому элементу строки. Мы рассмотрим 3 варианта работы с элементами объектов класса QString:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <QTextStream> int main() { QTextStream out(stdout); QString str = "There are many stars."; // Способ №1 foreach (QChar qc, str) { out << qc << " "; } out << endl; // Способ №2 for (QChar *it=str.begin(); it!=str.end(); ++it) { out << *it << " " ; } out << endl; // Способ №3 for (int i = 0; i < str.size(); ++i) { out << str.at(i) << " "; } out << endl; return 0; } |
Результат выполнения программы:
Способ №1: Ключевое слово foreach является расширением языка C++ средствами Qt. Первый параметр — это один символ строки, а второй — строка, которую мы будем перебирать посимвольно:
1 2 3 |
foreach (QChar qc, str) { out << qc << " "; } |
Способ №2: Использование итераторов:
1 2 3 |
for (QChar *it=str.begin(); it!=str.end(); ++it) { out << *it << " "; } |
Способ №3: Используем цикл for, где с помощью метода size() получаем допустимые границы перебора, а с помощью метода at() — доступ к символам строки:
1 2 3 |
for (int i = 0; i < str.size(); ++i) { out << str.at(i) << " "; } |
Сравнение строк
Статический метод QString::compare()
используется для сравнения двух строк и возвращает целочисленное значение.
Если возвращаемое значение меньше 0
, то первая строка меньше второй.
Если возвращаемое значение больше 0
, то первая строка больше второй.
Если возвращается 0
, то строки совпадают.
Под словом «меньше» подразумевается, что в таблице символов выбранный символ одной строки предшествует соответствующему выбранному символу другой строки. Сами строки сравниваются следующим образом: сначала сравниваются первые символы двух строк — если они совпадают, то сравнивается следующая пара символов, и так до тех пор, пока не найдем отличающиеся символы или не переберем все символы до конца. С помощью метода compare() мы проведем 2 сравнения: учитывая и не учитывая регистр букв.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#include <QTextStream> // Добавляем для лучшей читабельности кода const int STR_EQUAL=0; int main() { QTextStream out(stdout); // Будем сравнивать следующие 3 строки QString a = "Rain"; QString b = "rain"; QString c = "rain\n"; // Первое сравнение - отличие сразу же в первом символе if (QString::compare(a, b) == STR_EQUAL) { out << "a, b are equal" << endl; } else { out << "a, b are not equal" << endl; } out << "In case insensitive comparison:" << endl; // С помощью флага Qt::CaseInsensitive отключаем чувствительность к регистру if (QString::compare(a, b, Qt::CaseInsensitive) == STR_EQUAL) { out << "a, b are equal" << endl; // и получаем равные строки } else { out << "a, b are not equal" << endl; } if (QString::compare(b, c) == STR_EQUAL) { out << "b, c are equal" << endl; } else { out << "b, c are not equal" << endl; } // Удаляем символ новой строки в строке c c.chop(1); out << "After removing the new line character" << endl; if (QString::compare(b, c) == STR_EQUAL) { out << "b, c are equal" << endl; // теперь наши строки равны } else { out << "b, c are not equal" << endl; } return 0; } |
Результат выполнения программы:
Конвертация строк
Класс QString содержит следующие методы: toInt(), toFloat() и toLong(), которые позволяют преобразовать строку в типы int, float и long int соответственно. Метод setNum() позволяет конвертировать различные числовые данные в строку. Данный метод является перегруженным, поэтому компилятор сам позаботится о том, чтобы вызвать подходящий вариант этого метода. В следующем примере мы конвертируем две строки в целочисленный тип данных, а затем складываем получившиеся числа. После этого мы уже выполняем обратную конвертацию: из чисел в строки и соединяем уже строки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <QTextStream> int main() { QTextStream out(stdout); // Наши строки QString s1 = "12"; QString s2 = "15"; QString s3, s4; // С помощью метода toInt() конвертируем строки в целочисленный тип данных, а затем складываем получившиеся числа out << s1.toInt() + s2.toInt() << endl; int n1 = 30; int n2 = 40; // С помощью метода setNum() выполняем конвертацию из целочисленного типа данных в QString, а затем соединяем уже строки out << s3.setNum(n1) + s4.setNum(n2) << endl; return 0; } |
Результат выполнения программы:
Буквы
Символы можно разделить на несколько категорий: цифры, буквы, пробелы и знаки пунктуации. Напомню, что объекты класса QString состоят из элементов типа QChar. Тип QChar предоставляет нам методы isDigit(), isLetter(), isSpace() и isPunct(). В следующем примере мы, используя небольшую строку, подсчитаем количество цифр, букв, пробелов и знаков пунктуации, входящих в нее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <QTextStream> int main() { QTextStream out(stdout); // Создаем по одной переменной для каждой категории символов int digits = 0; int letters = 0; int spaces = 0; int puncts = 0; // Исходная строка QString str = "7 white, 3 red roses."; // Выполняем посимвольный перебор строки foreach(QChar s, str) { // Используем необходимые методы для сортировки символов по соответствующим категориям if (s.isDigit()) { digits++; } else if (s.isLetter()) { letters++; } else if (s.isSpace()) { spaces++; } else if (s.isPunct()) { puncts++; } } // Выводим результат на экран out << QString("There are %1 characters").arg(str.count()) << endl; out << QString("There are %1 letters").arg(letters) << endl; out << QString("There are %1 digits").arg(digits) << endl; out << QString("There are %1 spaces").arg(spaces) << endl; out << QString("There are %1 punctuation characters").arg(puncts) << endl; return 0; } |
Результат выполнения программы:
Модификация строк
Одни методы (например, toLower()) возвращают новую модифицированную копию исходной строки. Другие методы модифицируют непосредственно исходную строку. Далее мы рассмотрим пример, в котором будет использоваться второй тип методов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include <QTextStream> int main() { QTextStream out(stdout); // Исходная строка QString str = "Lovely"; // С помощью метода append() добавляем новую строку в конец исходной строки str.append(" season"); out << str << endl; // С помощью метода remove() удаляем 3 символа, начиная с позиции №10 исходной строки str.remove(10, 3); out << str << endl; // С помощью метода replace() заменяем 3 символа, начиная с позиции №7 исходной строки str.replace(7, 3, "girl"); out << str << endl; // Очищаем строку str.clear(); if (str.isEmpty()) { out << "The string is empty" << endl; } return 0; } |
Результат выполнения программы:
Выравнивание строк
Для выравнивания строк используются методы leftJustified() и rightJustified(). В следующем примере мы выполним выравнивание первых частей (подстрок) каждой строки по правому краю:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <QTextStream> int main() { QTextStream out(stdout); QString field1 = "Name: "; QString field2 = "Occupation: "; QString field3 = "Residence: "; QString field4 = "Marital status: "; // Вычисляем размер самой широкой строки int width = field4.size(); out << field1.rightJustified(width, ' ') << "Robert\n"; out << field2.rightJustified(width, ' ') << "programmer\n"; out << field3.rightJustified(width, ' ') << "New York\n"; out << field4.rightJustified(width, ' ') << "single\n"; return 0; } |
Результат выполнения программы:
Метод rightJustified() возвращает строку размером width
, которая содержит символ-заполнитель, за которым следует строка. В нашем случае этим символом-заполнителем является пробел. Если строка короче, то остаток заполняется символом-заполнителем:
1 |
out << field1.rightJustified(width, ' ') << "Robert\n"; |
Управляющая последовательность символов
В Qt5 существует метод toHtmlEscaped(), который конвертирует обычную текстовую строку в HTML-строку, содержащую следующие HTML-метасимволы: <
, >
, &
, и "
, заменяя их HTML-мнемониками. Ниже представлена программа на языке Cи, код которой содержит HTML-метасимволы:
1 2 3 4 5 6 7 8 9 |
// Файл cprog.c #include <stdio.h> int main() { for (int i=1; i<=10; i++) { printf("Bottle %d\n", i); } } |
Наша следующая программа читает вышеприведенный файл и заменяет HTML-метасимволы их HTML-мнемониками:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// Файл html_escape.cpp #include <QTextStream> #include <QFile> int main() { QTextStream out(stdout); QFile file("cprog.c"); if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading"); return 1; } QTextStream in(&file); QString allText = in.readAll(); out << allText.toHtmlEscaped() << endl; file.close(); return 0; } |
Результат выполнения программы:
На этом всё. До следующего урока!
Добрый день!
При запуске проекта у меня не появляется черной консоли, есть результат в «Вывод приложения», а также в терминале, если поставить галочку в Проекты->Запускать в терминале. Но нет консольного окна как у Вас? Что можно сделать в этом случае?
Оказывается для того что бы это строчка работала:
надо cprog.c запихнуть в папку build которая создается возле папки с проектом.
Если располагать файл в папке проекта, то следует писать:
Здравствуйте, делал по вашей инструкции, только на сегодняшний день пришлось скачать более новую версию. Тут отсутствует QStringRef. Нашел что его можно заменить QStringView.
В последний версиях Qt (6.2.2) класс QStringRef был перемещен из Qt6Core в Qt6Core5Compat. Чтобы класс заработал подключи Qt6Core5Compat.
Вроде бы доходчиво все объяснено, НО мне не понравилась последняя подтема, где было чтение из файла. Объяснено было только преобразование строки, а создание объекта файла, его открытие и создание потокового ввода для файла было будто проигнорировано. Пришлось лезть в официальную документацию и смотреть каждый класс и функцию по отдельности, чтобы все понять до конца.
А так урок хороший, спасибо большое
Не могу понять почему endl работает. ( у меня не работает)
Мы создали обьект оut для вывода обьектов QString, но endl мы не перегружали, почему он у вас в примере работает?
Попробуй Qt::endl
Я бы даже предложил использовать
>>Мы создали обьект оut для вывода обьектов QString, но endl мы не перегружали, почему он у вас в примере работает?
Потому что мы использует не стандартный си-шный out, а out из подключенного заголовочного файла QTextStream. А в нём всё уже перегружено, как надо.
>>Не могу понять почему endl работает. ( у меня не работает)
Не знаю. Только что скомпилировал самый первый пример, всё работает (ниже прикрепил ссылку на скриншот):
https://ibb.co/9TJpYn0
P.S.: Да, компилятор ругался, что обычный endl уже устарел и его стоит заменить на Qt::endl, но у меня на Qt 5.15.2 всё нормально скомпилировалось и работает. Может у вас более новая версия, тогда попробуйте Qt::endl.
Отлично! Многие рекомендуют .
Но вот вопрос, как настроить компиляцию min-GW и сборку cmake с поддержкой 14 Стандарта плюсов в QT Creator?
Спасибо . очень интересно.
Вопрос : где должен находиться файл cprog.c ?
Qt под Windows.
Добрый день.
Вариант 1:
Когда вы скомпилировали вашу программу, то рядом с папкой проекта должна появиться еще одна папка с названием типа:
"build-НАЗВАНИЕ_ВАШЕГО_ПРОЕКТА-Desktop_Qt_5_13_0_MinGW_32_bit-Debug"
Вот в неё и нужно положить файл cprog.c.
Вариант 2:
Файл может лежать где угодно, но тогда нужно прописать полный путь до него, заменив строчку:
на
Спасибо ! Вариант 1 заработал !
Всегда пожалуйста 🙂
Ну что скажу….прекрасно!… все четко и очень доходчиво…надеюсь и дальнейшие уроки так же изложены.. Спасибо!
Спасибо большое! 🙂
Куда в проект нужно положить файлик, прописанный в qfile. И как отобразить это в .pro?
Положен в источники, но программа его там не видит. Ругается
12:35:20: Starting D:\DOCUMENTS\jane_home\qt_experiments\String\install_2\debug\String_2.exe …
12:35:20: The process failed to start. Either the invoked program "D:/DOCUMENTS/jane_home/qt_experiments/String/install_2/debug/String_2.exe" is missing, or you may have insufficient permissions to invoke the program.
12:35:20: Cannot execute "": Не удается найти указанный файл.
12:35:20: D:/DOCUMENTS/jane_home/qt_experiments/String/install_2/debug/String_2.exe exited with code -1
Есть проблема. При создании проекта создаются 2 файла:
main.cpp
project000.qbs
файла project000.pro не создаётся
почему и как это исправить?
Под какую ОС установлен Qt? Windows или Linux?
Спасибо за урок! Жду следующий.
то что мне нужно, в рунете почти ничего нет по Qt
Обычно не оставляю комментов, НО, тут исключительный случай! Выражаю лютую благодарность за то, что Вы, как немногие на рунете, начали выкладывать бесплатно уроки по Qt. Спасибо! Надеюсь, что будут затронуты многие возможности этой библиотеке в рамках этого курса!
Спасибо большое 🙂
четвертый способ прохождения по контейнеру "стандартный
for
в стилеforeach
":ЗЫ: как писать код в комментариях?
Добрый день! А что в данной IDE прописать чтоб вывод русских символов было не кириллицей?
Когда следующий урок?)
Думаю, что в конце недели.