Строки. Сравнение строк

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

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

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

Пустая строка является строкой, которая имеет 0 символов.


Сравнение строк

Две строки сравниваются символ за символом с использованием кодов символов (например, ASCII или Unicode). В процессе сравнения используются следующие правила:

  1. Сравнение посимвольно:

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

    • При сравнении строк обычно учитывается регистр символов, что означает, что символы верхнего и нижнего регистра считаются разными.
    • Например, строки "hello" и "Hello" будут считаться разными из-за различия в регистре первой буквы.
       
  3. Определение отношений между строками:

    • Если две строки имеют одинаковую длину и все символы совпадают, то строки считаются равными.
    • Если строки имеют разную длину, сравнение определяется первым символом, который отличается.
    • Если первый отличающийся символ в первой строке имеет меньший код символа, то первая строка считается "меньше" по лексикографическому порядку.
    • Если первый отличающийся символ в первой строке имеет больший код символа, то первая строка считается "больше" по лексикографическому порядку.
Например: "паровоз"  < "пароход", потому что слова различаются в пятой букве и "в" < "х".

Библиотека string в C++

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

Подключение библиотеки

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

#include <string> 

 

Примечание

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



Создание и инициализация строк

Для создания строки используется класс string. Давайте рассмотрим несколько способов создания и инициализации строк:

string str1;     // пустая строка
string str2 = "Hello, world!";    // инициализация с использованием литерала (константного значения)
string str3("Welcome");     // инициализация с использованием конструктора
string str4(str2);     // копирование строки str2 в новую строку str4
string str5(5, 'h');   // создания строки из повторяющихся символов (в данном случае str5 = "hhhhh")



Ввод строк с клавиатуры и вывод на экран

Для ввода строк с клавиатуры в C++, вы можете использовать объект класса getline из библиотеки <string>.
 

Пример кода для ввода строки и вывода ее на экран
 
#include <iostream>
#include <string>

using namespace std;

int main()
{
    string input;
    cout << "Введите строку: ";
    getline(cin, input);
    cout << "Вы ввели: " << input << endl;
    return 0;
} 


В этом примере:

  1. Мы включаем заголовочные файлы <iostream> и <string>, чтобы иметь доступ к функциональности ввода-вывода и работы со строками.
  2. Создаем объект input типа string, который будет содержать введенную строку.
  3. С помощью cout выводим приглашение для ввода строки.
  4. С помощью getline(cin, input) считываем строку, введенную пользователем, и сохраняем ее в переменной input.
  5. Используя cout, выводим введенную строку на экран.

Обратите внимание, что getline читает всю строку, включая пробелы, до нажатия клавиши Enter. Вводить строку можно и с помощью cin, в данном случае будет считана строка только до первого пробела.

Разделение строки на части

В языке C++ для ввода строки можно использовать и стандартный поток ввода - cin. Однако есть недостаток: таким образом мы считаем только все символы до первого пробела! Это ограничение можно преобразовать в преимущество, если мы знаем, сколько слов в строке. Словом будем называть последовательность символов, разделенную пробелом или началом (концом) строки. В этом случае, можно легко получить все слова в отдельные переменные.
 
Пример
Если нам известно, что входная строка состоит из двух слов, разделенных пробелом, то мы можем сразу считать эти слова в отдельные переменные:
cin >> word1 >> word2;
Повторим, что это работает, когда вы заранее знаете, что строка содержит два слова и они разделены пробелом.

Конкатенация (сложение) строк

Для объединения двух строк в C++ можно использовать оператор + или метод append().
 

string str1 = "Hello";
string str2 = "world!";
string result1 = str1 + ", " + str2; // используя оператор +
string result2 = str1.append(", ").append(str2); // используя метод append()

// Результат: "Hello, world!"  


Обратите внимание, что метод append() изменяет исходную строку, добавляя к ней другую строку.
 

Сложение символов

В C++, символы типа char и строки типа string имеют разные поведения и свойства. Сложение символов напрямую не приведет к конкатенации, так как символы интерпретируются как числа (ASCII коды) и с этими числами будут выполняться арифметические операции.

Если мы бы написали char1 + char2 + char3, то это привело бы к сложению ASCII кодов символов, а не к конкатенации символов. Например, символ 'H' имеет ASCII код 72, 'e' - 101, и 'y' - 121. Таким образом, результат выражения char1 + char2 + char3 был бы 294, что представляет собой символ, не имеющий понятного отображения.

Чтобы правильно конкатенировать символы в строку, нам нужно использовать конструктор string(1, char1), который используется, чтобы создать временную строку из одного символа char1. Затем мы используем оператор + для конкатенации строк и символов.
 

Пример программы формирования строки из символов
#include <iostream>
#include <string>

using namespace std;

int main() {
    char char1 = 'H';
    char char2 = 'e';
    char char3 = 'y';

    string result = string(1, char1) + char2 + char3;

    cout << "Результат: " << result << endl;

    return 0;
}


Тот же результат можно получить записав немного по-другому:

 ...
    string result = ("" + char1) + char2 + char3;
 ...


Пояснение:

  1. "" + char1 - Здесь пустая строка "" складывается со значением символа char1. Такое сложение возможно, так как пустая строка является строкой, а char1 представляет собой символ. Таким образом, результат этой операции будет строка, состоящая из одного символа.

  2. ("" + char1) + char2 - К результату предыдущей операции (строка из одного символа) добавляется символ char2, таким образом, получается строка, состоящая из двух символов.

  3. ((char1 + char2) + char3) - К результату предыдущей операции добавляется символ char3, окончательно формируя строку из трех символов.

Итак, в итоге в строку result будет записана новая строка, состоящая из символов char1, char2 и char3.

Длина строки

Библиотека string предоставляет несколько полезных методов для получения информации о строке:

  • length(): возвращает длину строки.
  • size(): возвращает количество символов в строке.
  • empty(): проверяет, является ли строка пустой.

Пример использования методов получения информации о строке:

string str = "Hello, world!";
int len = str.length(); // len = 13
int size = str.size(); // size = 13
bool isEmpty = str.empty(); // isEmpty = false 

Обращение к символам строки

В C++, для обращения к символам строки по индексу можно использовать оператор квадратных скобок [] или функцию at().

Вот краткий пример кода, демонстрирующий обращение к символам строки по индексам:

#include <iostream>
#include <string>

using namespace std;

int main() 
{
    string str = "Hello, World!";
    
    char firstChar = str[0]; // Обращение к первому символу по индексу 0
    char fifthChar = str.at(4); // Обращение к пятому символу по индексу 4
    
    cout << "Первый символ: " << firstChar << endl;
    cout << "Пятый символ: " << fifthChar << endl;
    
    return 0;
}

В этом примере:

  1. Мы создаем строку str с содержимым "Hello, World!".
  2. С помощью оператора [ ] мы можем обратиться к символу строки по его индексу. Например, str[0] возвращает первый символ строки.
  3. С помощью функции at() мы также можем получить символ строки по индексу. Например, str.at(4) возвращает пятый символ строки.
  4. Затем мы выводим полученные символы на экран с помощью std::cout.

Обратите внимание, что индексы символов начинаются с 0. Таким образом, первый символ имеет индекс 0, второй символ – индекс 1 и так далее. Также стоит учитывать, что попытка доступа к символу с недопустимым индексом может привести к ошибке или неожиданному поведению, поэтому всегда следует проверять границы строки перед обращением к символам по индексу.

Перебор всех символов

Для перебора символов в строке в C++, можно использовать цикл for или while в сочетании с индексацией строки.

Примеры итерации по строке

1)  Цикл for для итерации через индексы символов строки

#include <iostream>
#include <string>

using namespace std;

int main() 
{
    string str = "Hello, World!";
    
    for (size_t i = 0; i < str.length(); i++) 
    {
        cout << str[i] << " ";
    }
    
    return 0;
}

В этом примере:

  1. Мы создаем строку str, которую хотим перебирать.
  2. Используя цикл for и переменную i, проходим по каждому индексу символа от 0 до str.length() - 1.
  3. Внутри цикла выводим символ на экран с помощью cout.
  4. Обратите внимание, что мы используем str.length() для получения длины строки.
  5. В результате каждый символ строки будет выведен на экран через пробел.
  6. Тип данных size_t используется для представления размеров объектов в памяти. Он является беззнаковым целочисленным типом. Этот тип обеспечивает переносимость кода между различными компиляторами и платформами, так как размеры объектов могут различаться в зависимости от архитектуры и операционной системы.
    Так как size_t беззнаковый тип, то запись цикла для итерации с конца строки в виде:
    for (size_t i = str.length() - 1; i >= 0; i--) 
    
    приведет к ошибке. Так как size_t является беззнаковым целочисленным типом, и значение переменной этого типа всегда будет больше или равно нулю. В результате выражение i >= 0 всегда истинно, что приведет к бесконечному циклу. Чтобы исправить эту проблему, можно использовать знаковый целочисленный тип, такой как int:
    for (int i = (int)str.length() - 1; i >= 0; i--)

 

2) Диапазонный цикл for (C++11 и выше) для итерации через символы строки:

#include <iostream>
#include <string>

using namespace std;

int main() 
{
    string str = "Hello, world!";
    
    for (char c : str) 
    {
        cout << c << " ";
    }
    
    return 0;
}

Поясним в этом примере только строчку с диапазонным циклом for:

  • for: Это ключевое слово начала цикла.
  • (char c : str): Это часть объявления цикла, где char c является объявлением переменной итерации, которая будет использоваться для хранения каждого символа строки по очереди. str - это строка, через которую будет проходить цикл.

Цикл "диапазонного for" является сокращенным способом итерации по контейнеру (или диапазону) значений в языке C++. В данном случае, строка str рассматривается как контейнер символов, и цикл перебирает каждый символ, присваивая его переменной c.

Каждую итерацию цикла переменная c принимает значение текущего символа строки str. Внутри тела цикла (внутри фигурных скобок {}) вы можете выполнять операции с переменной c, которая представляет текущий символ строки.

 

Задача
Во входной строке заменить все символы 'a' на символы 'b'. 
#include <iostream>
#include <string>

using namespace std;

int main() 
{
    string s;
    cin >> s;

    for (size_t i = 0; i < s.length(); ++i) 
    {
        if (s[i] == 'a') 
        {
            s[i] = 'b';
        }
    }

    cout << s << endl;

    return 0;
}
В данной программе цикл for с переменной i перебирает индексы символов в строке s. Внутри цикла проверяется символ с индексом i, и если он равен 'a', то символ заменяется на 'b'. Таким образом, изменение символов происходит  непосредственно внутри строки s.