Печатать книгуПечатать книгу

§ 9. Строковые величины

Сайт: Профильное обучение
Курс: Информатика. 10 класс (Повышенный уровень)
Книга: § 9. Строковые величины
Напечатано:: Гость
Дата: Понедельник, 29 Апрель 2024, 23:26

9.1. Ввод, вывод, присваивание строковых величин

Cо строковым типом данных вы познакомились в прошлом году. В языке С++ тоже есть тип данных, который позволяет работать со строковыми величинами. Переменные строкового типа в С++ описываются типом string (так же, как и в Pascal). Для работы с переменными типа string требуется подключить библиотеку, имя которой совпадает с именем типа: string.

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

string <имя строки>;

Если строка не содержит служебных символов, то ее можно вводить с помощью команды cin. Если в строке содержатся пробелы, или символы табуляции, или другие служебные символы, то в строку будут переданы символы до первого служебного, остальные символы будут проигнорированы. Для ввода строки со служебными символами используют команду

getline(cin, s);

Первый параметр этой команды — имя потока для ввода, а второй — имя переменной, в которую будет записана строка. Ввод заканчивается нажатием клавиши Enter. Символ, соответствующий нажатию этой клавиши, считывается, но к строке не добавляется. Для вывода строк используется команда cout (пример 9.1).

С помощью команды присваивания переменной строкового типа можно присвоить значение. Значение строковой величины записывается в двойных кавычках. Пустая строка задается следующим образом:

s = "";

Запись поясняющего текста при выводе в команде cout является строковой константой. К символам в строке можно обращаться, используя индекс. Нумерация символов начинается с нуля, s[i] соответствует i-му символу в строке s.

Пример 9.1. Введем две строки (с помощью разных команд) и выведем их значения.

#include <iostream>

#include <string>

using namespace std;

 

int main()

{

  string s1, s2;

  cout << "1 stroka" << endl;

  getline(cin, s1);

  cout << "2 stroka" << endl;

  cin >> s2;

  cout << "1 stroka - " << s1 << endl;

  cout << "2 stroka - " << s2 << endl;

  return 0;

}

Тестирование:

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

Если поменять местами команды вывода (сначала cin, потом getline), то результат будет следующим:

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

Если возникает необходимость использовать команду  cin  вводится число, а затем с помощью getline сразу после команды cin, то нужно предварительно очистить буфер данных. Это можно сделать с помощью команды cin.ignore(200,'\n'); Первый параметр указывает, какое максимальное количество символов нужно проигнорировать, пока не встретится символ, указанный в качестве второго параметра.

Команда cin.ignore(); (без параметров) игнорирует символ  '\n'. Это может быть нужно, когда сначала с помощью  cin  вводится число, а затем с помощью getline  считываются строки.

  cin >> n;

  cin.ignore();

  for (int i = 0; i < n; i++){

    getline(cin, s);

    

  }

Без cin.ignore() первая строка будет пустой.

 

9.2. Сравнение и сложение строковых величин

Так же, как и для других типов данных, для строк определены свои операции — действия, которые можно выполнять с данными типа string. Для строкового типа такими операциями являются сравнение и сложение.

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

При сравнении строк следует помнить, что заглавные и строчные буквы — это разные буквы, поскольку имеют различные номера в таблице символов. Поэтому строки "mama" и "Mama" будут различными, а неравенство "mama" > "Mama" — верным (у буквы 'm' код 109, а у 'М' — 77). Для проверки правильности сравнения строк можно воспользоваться программой из примера 9.3.

Для строк определена операция сложение (конкатенация). Обозначается она знаком «+». В результате сложения двух строк получается новая строка, в которой после символов первой строки будут записаны символы второй строки. Результат данной операции зависит от порядка слагаемых (пример 9.4).

Пример 9.5. Написать программу, которая просит ввести название государства и его столицу, а затем выводит сообщение:

Столица государства … — город … .

Вместо многоточия должны быть выведены соответствующие значения.

Этапы выполнения задания

I. Исходные данные: переменные str (название государства) и gor (название города).

II. Результат: переменная s (итоговая строка).

III.  Алгоритм решения задачи.

1. Ввод исходных данных. 
2. Создание итоговой строки. 
3. Вывод строки.

IV. Описание переменных: str, gor, s – string.

Пример 9.2. Примеры сравнения строк.

s1 s2 Результат

"string"

"char"

s1 > s2

"строка"

"Строка"

s1 > s2

"book"

"Magazine"

s1 > s2

"book"

"magazine"

s1 < s2

"липа"

"лист"

s1 < s2

"леска"

"лес"

s1 > s2

"112"

"7"

s1 < s2

"123"

"11111111"

s1 > s2

"123"

"123"

s1 = s2

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

#include <iostream>

#include <string>

 

using namespace std;

 

int main()

{

  string s1, s2;

  cout << "1 stroka" << endl;

  getline(cin, s1);

  cout << "2 stroka" << endl;

  getline(cin, s2);

  if (s1 > s2)

    cout << "s1 > s2" << endl;

  else

    if (s1 < s2)

      cout << "s1 < s2" << endl;

    else

      cout << "s1 = s2" << endl;

  return 0;

}

Эта программа будет корректно работать как для латинских символов, так и для русских, невзирая на то что команды для работы с русскими буквами не подключены. Это можно объяснить тем, что относительный порядок символов соответствует алфавитному. Поэтому какой бы код не имела буква «Б», она будет после буквы «А». Исключением является буква «ё». В разных кодовых таблицах она может располагаться или до всех русских букв, или после них.

Пример 9.4. Примеры сложения строк.

#include <iostream>

#include <string>

 

using namespace std;

 

int main()

{

  string s1 = "Pasha";

  string s2 = "Ivanov";

  string s3 = s1 + " " + s2;

  string s4 = s2 + " " + s1;

  cout << "s3 - " << s3 << endl;

  cout << "s4 - " << s4 << endl;

  return 0;

}

Тестирование:

Пример 9.5.  

V. Программа:

#include <iostream>

#include <string>

#include <windows.h>

 

using namespace std;

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  string str, gor;

  cout << "название государства" << endl;

  cin >> str;

  cout << "название столицы" << endl;

  cin >> gor;

  string s = "Столица государства "

         + str + " — город " + gor;

  cout << s << endl;

   return 0;

}

 VI. Тестирование

9.3. Поиск в строке

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

В классе string реализовано несколько различных функций, которые позволяют осуществлять поиск символа или подстроки (части строки) в строке. В качестве результата получаем номер первого вхождения искомого образца или значение –1, если образец не найден. Значение –1 поисковые функции возвращают только для компилятора MinGW. Универсальным возвращаемым значением, которое поддерживается компиляторами по стандарту, является константа string::npos.

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

Функция

Описание
length() Определяет длину строки (количество символов в строке)
find(s1) Определяет позицию подстроки s1
rfind(s1) Определяет позицию последнего (первого при просмотре справа налево) вхождения подстроки s1
find(s1,from) Определяет позицию подстроки s1. Поиск начинается с позиции from

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

В примере 9.6. показано, как применять указанные функции.

Пример 9.7. Написать программу, которая вводит слово, а затем выводит его по одному символу в строке.

Этапы выполнения задания

I. Исходные данные: переменная s — исходное слово.

II. Результат: слово на экране, каждый символ в отдельной строке.

III.  Алгоритм решения задачи.Описание переменных: s – string, n – int.

1. Вводим исходные данные. 
2. Определяем длину слова. Переменной n присваиваем значение функции length() 
3. В цикле for выводим по одному символы введенного слова.

Пример 9.8. Написать программу, которая выводит на экран последний символ введенного слова и определяет, встречается ли этот символ в слове еще раз. Если встречается, то программа выводит индекс этого символа.

Этапы выполнения задания

I. Исходные данные: переменная s — введенное слово.

II. Результат: последний символ в слове и соответствующее сообщение: встречается или не встречается.

III.  Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
Определим длину слова. Переменной n присваиваем значение функции length.
3. 
В цикле for выводим по одному символу введенного слова.
4. 
Определим последний символ.
5. 
Определим позицию последнего символа в слове. Переменной k1 присваиваем значение функции find для поиска последнего символа. Переменной k2 присваиваем значение функции rfind для последнего символа.
Если k1 = k2, то символ в слове единственный, иначе в слове есть другой такой же символ.
6. Вывод результата.

 IV. Описание переменных: s — string, n, k1, k2 — int.

Язык С++ является объектно-ориентированным языком. Тип данных string не является частью языка С++, а реализован как шаблонный класс, входящий в стандартную библиотеку STL. С понятием класса вы познакомитесь позже. При описании класса определяется не только способ хранения данных, но и методы обработки этих данных. Методы реализованы в виде функций, доступ к которым имеет любая переменная, являющаяся объектом данного класса. Для вызова функции ее имя указывают после имени переменной, разделяя их точкой. Например: s.length(), s.find('*') и др. В окне редактора кода список функций, относящихся к переменной типа string, может открываться, когда после имени переменной поставили точку. После чего функцию можно выбрать из списка.

Для того чтобы список функций появился в Code::Bloks, нужно прописать дополнительное пространство имен:

   using namespace std::__cxx11;  

Пример 9.6. Примеры использования функций.

string s ="informatics";

int n = s.length();

n=11

 string s ="Не слово хозяин хозяину, 
            а хозяин слову хозяин"
;

 string s1 = "хозяин";

 int n = s.length();

 int p1 = s.find(s1);

 int p2 = s.rfind(s1);

 int p3 = s.find(s1, 14);

n=46

p1=9

p2=40

p3=16

 

Пример 9.7.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string s;

  cout << "slovo" << endl;

  cin >> s;

  int n = s.length();

  for (int i = 0; i< n; i++)

    cout << s[i] << endl;

  return 0;

}

VI. Тестирование.

Пример 9.8.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string s;

  cout << "slovo" << endl;

  cin >> s;

  int n = s.length();

  int k1 = s.find(s[n-1]);

  int k2 = s.rfind(s[n-1]);

  if (k1 ==k2)

    cout << " 1 raz" << endl;

  else

     cout << "est, pos - " << k1 << endl;

  return 0;

}

IV. Тестирование.

9.4. Копирование, вставка, замена и удаление символов

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

Команда Описание
substr(n, k) Копирует часть строки в другую строку
erase(n, k) Удаляет символы строки
insert(n, s1) Вставляет подстроку s1 в строку  
replace(n, k, s1) Заменяет символы строкой s1
Empty() Возвращает true, если строка пуста, false — если не пуста
Push_back(c) Добавляет в конец строки символ с
Pop_back() Удаляет один символ в конце строки

Во всех командах переменная n обозначает позицию (номер) символа, начиная с которого выполняют операцию, а переменная k — количество символов. Разберем команды подробнее (пример 9.9).

В результате выполнения команды substr строка s не изменяется. Результат работы функции присваивается другой строке.

Команды erase, insert и replace изменяют исходную строку s.

В примере 9.10 показано, как применяются указанные команды.

Функции insert и replace имеют еще один вариант реализации. Этот вариант позволяет использовать при вставке не всю строку s1, а только ее часть. В этом случае задаются два дополнительных параметра: позиция n1 и количество символов k1, относящихся к строке s1. Параметры позволяют выделить подстроку в строке s1, которая и вставляется в исходную строку:

insert(n, s1, n1, k1),

replace(n, k, s1, n1, k1).

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

Этапы выполнения задания

I. Исходные данные: переменная s — исходная строка, p — исходная подстрока.

II. Результат: k — искомое количество.

III.  Алгоритм решения задачи.

1. Вводим исходные данные. 
2. Инициализируем значение счетчика k = 0.
3. Определяем длины n1 и n2 для строки s и подстроки p.
4. В цикле for от 1 до разницы в длинах строки s и подстроки p.

4.1. Выделим из строки s подстроку t такой же длины, что и длина p, начиная с текущего символа. 
4.2. Сравним подстроки. Если они равны, то увеличиваем значение счетчика на 1.

5. Вывод результата.

IV. Описание переменных: s, p, t — string, n1, n2, k — int.

Пример 9.9. Команды для преобразования строк.

1. Запись s1 = s.substr(n, k); означает, что в строке s выделяют k символов, начиная с символа, индекс которого записан в переменной n. Символы копируются в переменную s1 (действие команды сравнимо с копированием фрагмента текста в буфер обмена).

2. Запись s.erase(n, k); означает, что в строке s выделяют k символов, начиная с символа, индекс которого записан в переменной n. Выделенные символы удаляются из строки s. Остальные символы строки сдвигаются влево (действие команды сравнимо с удалением фрагмента текста).

3. Запись s.insert(n, s1); означает, что в строку s вставляют символы строки s1, вставка происходит в позиции n. Остальные символы строки сдвигаются вправо (действие команды сравнимо со вставкой фрагмента текста из буфера обмена в позицию курсора).

4. Запись s.replace(n, k, s1); означает, что символы строки s заменяют на символы строки s1. Заменяются k символов, начиная с символа, стоящего в позиции n. Остальные символы строки сдвигаются (действие команды сравнимо со вставкой фрагмента текста из буфера обмена на место выделенного фрагмента).

Пример 9.10. Примеры использования команд (команды применяются последовательно).

Исходная строка

 string s = "informatics";

Команда

Результат

 s1 = s.substr(2,5);

s1 = "forma"

 s.erase(2, 7);

s = "incs"

 s.replace(2, 2, "ion");

s = "inion"

 s1 = "format";

 s.insert(2, s1);

 s = "information"

Пример 9.11.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string s, p;

  cout << "stroka" << endl;

  getline(cin, s);

  cout << "podstroka" << endl;

  getline(cin, p);

  int n1 = s.length();

  int n2 = p.length();

  int k = 0;

  for (int i = 0; i < n1 - n2 + 1; i++){

    string t = s.substr(i, n2);

    if (== p)

      k++;

  }

  cout << k << " raz" << endl;

  return 0;

}

VI. Тестирование.

 

Эффективное решение данной задачи можно получить с помощью алгоритма КнутаМориса—Пратта (КНП-алгоритм)[1].


[1] Котов В. М., Лапо А. И., Быкадоров Ю. А., Войтехович Е. Н. Информатика, 9 класс. Минск: Народная асвета, 2019. С. 44.

9.5. Анализ текста на наличие различных символов

Современные текстовые редакторы позволяют получить статистику по символам и словам в документе (пример 9.12). Грамотный набор текста предполагает наличие одного пробела между словами. В таком тексте количество слов будет больше количества пробелов на единицу.

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

Этапы выполнения задания

I. Исходные данные: строка текста st.

II. Результат: количество слов k.

III. Алгоритм решения задачи. Описание переменных: st — string, n, k — int.

1. Вводим исходные данные.
2. 
Определяем длину строки.
3. 
Начальное значение счетчика k = 1 (в тексте есть хотя бы одно слово). 
4. 
С помощью цикла for просматриваем каждый символ в строке. Если текущий символ — пробел, то увеличиваем значение счетчика количества слов.
5. 
Вывод результата.

Пример 9.13. Написать программу, которая определит, каких знаков препинания в тексте больше: тех, которыми заканчивается предложение («.», «?», «!»), или тех, которые стоят внутри предложения («,», «:», «;»).

Этапы выполнения задания

I. Исходные данные: переменная st (текст).

II. Результат: сообщение о том, каких знаков больше.

III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
Определим длину строки.
3. 
Создадим две вспомогательные строки. В строку z1 запишем символы «.!?» (знаки препинания «первого вида»), а в строку z2 – «,:;» (знаки препинания «второго вида»).
4. 
Инициализируем два счетчика k1 и k2 нулями (для знаков препинания «.!?» и «,:;» вида).
5. 
В цикле for проверяем каждый символ строки st.

5.1. Если встретился знак препинания «.», «!» или «?», то увеличим значение счетчика k1 на 1.
5.2. Если встретился знак препинания «,», «:», «;», то увеличим значение счетчика k2 на 1. 
5.3. Для определения, встретился ли знак препинания, будем использовать функцию find, с помощью которой будем искать текущий символ в строке со знаками препинания.

6. Сравниваем полученные значения счетчиков и выводим результат.

IV. Описание переменных: st, z1, z2 – string, n, k1, k2 – int.

 

Пример 9.12. Статистика в документе Word (соответствующая команда на вкладке Рецензирование).

V. Программа:

#include <iostream>

#include <string>

#include <windows.h>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  string st;

  cout << "Текст" << endl;

  getline(cin, st);

  int n = st.length();

  int k = 1;

  for (int i = 0; i < n; i++)

    if (st[i] == ' ')

      k++;

  cout << "в тексте " << k;

  cout << " слов(-о,-а)" << endl;

  return 0;

}

VI. Тестирование (для проверки можно скопировать текст абзаца, из документа Word).

VII. Анализ результата. Если посмотреть статистику Word для этого абзаца, получим:

Пример 9.13.

V. Программа:

#include <iostream>

#include <string>

#include <windows.h>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  string z1 = ".!?", z2 = ",:;";

  int k1 = 0, k2 = 0;

  string st;

  cout << "Текст" << endl;

  getline(cin, st);

  int n = st.length();

  for (int i = 0; i < n; i++){

    if (z1.find(st[i]) != -1)

       k1++;

    if (z2.find(st[i]) != -1)

       k2++;

  }

  if (k1 > k2)

    cout << "Первого вида больше" << endl;

  else

    if (k1 < k2)

     cout << "Второго вида больше" << endl;

    else

     cout << "Одинаково" << endl;

  return 0;

}

VI. Тестирование (для проверки можно скопировать текст абзаца)[1].



[1] Чехов, А. П. Человек в футляре // http://ilibrary.ru/text/438/p.1/index.html (дата доступа: 28.07.2020).

9.6. Преобразование строк

Пример 9.14. По правилам орфографии новое предложение начинается всегда с заглавной буквы. Текстовые редакторы автоматизируют ввод заглавной буквы, т. е. если пользователь написал первое слово в предложении со строчной буквы, то она заменяется на заглавную. Написать программу, которая производит такую автозамену для текста, набранного латинским буквами. Считать, что текст набран корректно и после каждого знака препинания, означающего конец предложения («.», «!», «?»), стоит пробел.

Этапы выполнения задания

I. Исходные данные: переменная st (введенная строка).

II. Результат: преобразованная строка.

III.  Алгоритм решения задачи.

1. Ввод исходных данных. 
2. Вычисление длины строки. 
3. Для хранения символов конца предложения создадим строку z.
4. В цикле for проверяем каждый символ строки st.

4.1. Если текущий символ является символом конца предложения, то нужно заменить символ, стоящий на две позиции дальше, если этот символ — строчная буква. 
4.2. Символ с является строчной буквой тогда, когда выполнено условие ’a’  ≤ c ≤ ’z’ (для латинских букв) и ’a’  ≤ c ≤ ’я’   (для русских букв). 
4.3. Для замены символов можно воспользоваться тем фактом, что разница в кодах между заглавной и соответствующей ей строчной буквой равна 32. Для проверки и замены символов создадим функцию up_char.

5.Вывод результата.

IV. Описание переменных: st – string, n – int.

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

Пример 9.15. Написать программу, которая заменит в тексте каждую цифру 2 словом «two».

Этапы выполнения задания

I. Исходные данные: переменная st (введенный текст).

II. Результат: преобразованный текст.

 III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
В цикле while проверяем каждый символ текста st.

2.1. Если текущий символ текста «2», то удаляем его и вставляем подстроку «two». 
2.2.  Переходим к следующему символу.

 3. Вывод результата.

IV. Описание переменных: st – string, i – int.

При правильном наборе компьютерного текста между любыми двумя словами должен быть ровно один пробел. Однако иногда случайно вставляют несколько пробелов. В этом случае Word подчеркивает пробелы голубой волнистой линией (пример 9.16).

Пример 9.17. Написать программу, которая проверяет правильность расстановки пробелов в тексте и, если между словами более одного пробела, — удаляет лишние.

Этапы выполнения задания

I. Исходные данные: переменная st (введенный текст).

II. Результат: преобразованный текст.

III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. Поскольку длина строки будет изменяться при обработке строки, то количество повторений цикла заранее не известно. Будем использовать цикл while
3. В цикле while проверяем соседние символы текста st.

3.1. Если оба соседних символа являются пробелами, то удалим один из них. Соседние символы имеют индексы, отличающиеся на один: i и i + 1.
3.2. Поскольку в цикле есть обращение к элементу с номером i + 1, то условием выполнения цикла будет неравенство i < length(st) — 1.
3.3. Переходим к следующему символу только тогда, когда удаление не проводили.

4. Вывод результата.

VI. Описание переменных: st – string, i– int.

Пример 9.18. Написать программу, которая проверяет правильность расстановки пробелов вокруг тире. Если пробелы пропущены, то вставляет их. Предполагается, что в тексте нет слов, которые пишутся через дефис, двух знаков «-» подряд и лишних пробелов.

Этапы выполнения задания

I. Исходные данные: переменная st (введенный текст).

II. Результат: преобразованный текст.

III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
В цикле while проверяем каждый символ на совпадение с «-». При совпадении проверяем соседние символы.

2.1. Если соседний справа символ (i + 1) не пробел, то вставляем пробел. 
2.2. Если символ слева (i1) не пробел, то вставляем пробел и увеличиваем i на 1. 
2.3. Поскольку в цикле есть обращение к элементу с номером i + 1, то условием выполнения цикла будет неравенство i < length(st)-1
2.4. Поскольку в цикле есть обращение к элементу с номером i – 1, то начальное значение i = 1.

3. Переходим к следующему символу.
4.  Вывод результата.

IV. Описание переменных: st – string, i– int.

Пример 9.19. Написать программу, которая выведет слова-палиндромы [3] (слова, которые одинаково читаются слева направо и справа налево), входящие в заданный текст. Слова в тексте могут быть разделены одним или несколькими пробелами. Пробелы могут быть в начале и в конце текста.

Этапы выполнения задания

I. Исходные данные: переменная st (введенный текст).

II. Результат: слова-палиндромы.

 III. Алгоритм решения задачи.

1. Ввод исходных данных. 
2. Будем выделять первое слово из исходного текста, проверять его и затем удалять. 
3. Логическая переменная p изменит значение с false на true, если будет выведен палиндром. 
4. В цикле while, до тех пор пока строка не станет пустой, выполняем следующее.

4.1. Удалим пробелы в начале строки. Выделим первое слово из строки.
4.2. Проверим выделенное слово и, если оно является палиндромом, то выведем его. Слово может выделяться со знаками препинания («,.;:?!»), поэтому их нужно удалить перед проверкой его на палиндром. 
4.3. Удалим слово из строки.

5. Опишем три вспомогательных алгоритма.

5.1. Функцию DelSpace для удаления пробелов в начале строки. Пробелы удаляются из строки только тогда, когда она не пуста. Если пробелов в начале строки нет, то функция не изменит исходную строку. 
5.2. Функцию FirstWord, которая скопирует из строки первое слово. Если в строке только одно слово (нет пробелов), то оно же и является первым. 
5.3. Функцию CheckPalindrom для проверки, является ли слово палиндромом. Для проверки будем сравнивать первый символ с последним, второй с предпоследним и т. д. Символ с номером i будет сравниваться с символом с номером (n – i– 1), где n — длина слова.

6. Вывод сообщения «нет палиндромов» в случае, если значение p осталось false.

IV. Описание переменных: st, sl – string, i, n – int, p - bool.


[3] В мире интересных слов. Палиндромы. http://www.tramvision.ru/words/pal.htm.

Пример 9.14.

V. Программа:

#include <iostream>

#include <string>

#include <windows.h>

 

using namespace std;

using namespace std::__cxx11;

 

char up_char(char c)

{

  bool u1 = 'a' <= c && c <= 'z';

  bool u2 = 'а' <= c && c <= 'я';

  if (u1 || u2)

    return (- 32);

}

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  string st, z = ".?!";

  cout << "Text" << endl;

  getline(cin, st);

  int n = st.length();

  for (int i = 0; i < n - 2; i++)

    if (z.find(st[i]) != -1)

      st[i + 2= up_char(st[i + 2]);

  cout << endl << "New text" << endl;

   cout << st << endl;

  return 0;

}

VI. Тестирование [2].

Пример 9.15.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string st;

  cout << "Text" << endl;

  getline(cin, st);

  int i = 0;

  while (< st.length()){

    if (st[i] == '2'){

      st.erase(i,1);

      st.insert(i, "two");

    }

    i++;

  }

  cout << endl << "New text" << endl;

  cout << st << endl;

  return 0;

}

VI. Тестирование.

VII. Анализ результата.

Вместо двух функций erase и insert можно воспользоваться функцией replace.

   st.replace(i, 1, "two");   

Пример 9.16. Выделение лишних пробелов в Word.

Пример 9.17.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string st;

  cout << "Text" << endl;

  getline (cin, st);

  int i = 0;

  while (< st.length() - 1){

    if (st[i] == ' ' &&

        st[i + 1== ' ')

          st.erase(i, 1);

    else

      i++;

  }

  cout << endl << "New text" << endl;

  cout << st << endl;

  return 0;

}

VI. Тестирование.

Рассмотрим подробнее ситуацию, когда в тексте стоят подряд два или более пробелов. В примере такая ситуация встречается между словами «правильном» и «наборе». Условие (st[i] == ' ' && st[i + 1== ') для i = 14 выполнится, и пробел, стоящий на 14 месте, удалится. Тогда пробел, стоящий на месте 15, сдвинется влево и получит номер 14. При следующем выполнении тела цикла снова удалится пробел на месте 14, а пробел на месте 15 сдвинется влево. Переход на следующий символ осуществится только тогда, когда условие (st[i] == ' ' && st[i + 1== ' ') будет ложным — между словами останется только один пробел.

Пример 9.18.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string st;

  cout << "Text" << endl;

  getline(cin, st);

  int i = 1;

  while (< st.length() -1){

    if (st[i] == '-'){

      if (st[i + 1!= ' ')

        st.insert(+ 1, " ");

      if (st[i - 1!= ' '){

        st.insert(i, " ");

        i++;

      }

    }

    i++;

  }

  cout << endl << "New text" << endl;

  cout << st << endl;

  return 0;

}

 VI. Тестирование. Введите текст:

«Жизнь прожить-не поле перейти. Родимая сторона- мать, чужая -мачеха. Сделал дело — гуляй смело.»

Результат:

VII. Анализ результата. В примере встречаются все четыре возможных ситуации: пробелов нет ни слева, ни справа от тире; пробел только слева; пробел только справа; пробелы с двух сторон. В результате выполнения все пробелы расставлены правильно.

Пример 9.19.

V. Программа:

#include <iostream>

#include <string>

#include <windows.h>

 

using namespace std;

using namespace std::__cxx11;

 

string DelSpace (string s)

{

  while (!s.empty() && s[0]== ' ')

    s.erase(0, 1);

  return s;

}

 

string FirstWord (string s)

{

  int i = s.find(' ');

  if (!= 0)

    return s.substr(0, i);

  else

    return s;

}

 

bool CheckPalindrom(string s)

{

  int n = s.length();

  for (int i = 0; i < n / 2; i++)

    if (s[i] != s[- i - 1])

      return false;

  return true;

}

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  string st, z = ",.;:?!";

  cout << "Текст" << endl;

  getline(cin, st);

  bool p = false;

  while (!st.empty()){

    st = DelSpace(st);

    if (st.empty()) break;

    string sl = FirstWord(st);

    int n = sl.length();

    if (z.find(sl.back()) != -1)

      sl.pop_back();

    if (CheckPalindrom(sl)){

        cout << sl << endl;

        p = true;

    }

    st.erase(0, n);

  }

  if  (!p)

    cout << "нет палиндромов" << endl;

  return 0;

}

VI.  Тестирование. Введите текст:

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

Результат:



[2] Куприн, А. И. Гранатовый браслет // http://ilibrary.ru/text/1022/p.7/index.html

9.7. Преобразование строк в числа и чисел в строки

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

В строковых переменных легко производить такие операции, как удаление, вставка или замена символа. Вставка, замена или удаление цифры из числа производятся сложнее (задача о выделении цифр из числа рассматривалась в § 8 — см. пример 8.17). При необходимости число можно преобразовать в строку, выполнить нужные действия и преобразовать строку обратно в число.

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

Этапы выполнения задания

I. Исходные данные: переменная st (введенный текст).

II. Результат: сумма цифр или сообщение о том, что это не число.

III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
Вычисление длины строки (n).
3. 
К введенному тексту нельзя в явном виде применить функции преобразования типа, поскольку длина текста может быть больше 20, а простых числовых типов, содержащих такое количество цифр, язык С++ не поддерживает. Поэтому будем пытаться преобразовывать в число каждый введенный символ, считать сумму и количество тех символов, которые удалось преобразовать.
4. 
Инициализация переменных: s = 0 (сумма цифр числа) и k = n (переменная-флаг).
5. 
В цикле for проверяем каждый символ строки st.

5.1. Если текущий символ текста цифра, то преобразуем его в число, добавляем число к сумме. Символ строки является цифрой, если выполняется условие (st[i] >= '0' && st[i] <= '9').
5.2. Если символ не цифра, то запоминаем номер этого символа в переменной k и прерываем выполнение цикла.

6. Если после цикла k < n, то текст не является записью числа. Иначе выводим сумму цифр.

IV. Описание переменных: st – string, n, s, k – int.

Пример 9.22*. Написать программу, которая раскрывает скобки в числовом выражении и вычисляет его значение. Выражение имеет вид a + b + c + и вводится как строка. Вместо a, b и c — символы цифр, образующие целое число (количество цифр в каждом из них не более девяти, количество слагаемых — произвольное). Вывести значение выражения. Например, для выражения 5 + 17 + 8 должны получить: 30.

Этапы выполнения задания

I. Исходные данные: переменная st (текст).

II. Результат: числовое значение выражения.

III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
В цикле while, до тех пор, пока строка не станет пустой, выполняем следующее.

2.1. Найдем символ «+», символы до него скопируем в переменную s1
2.2. Преобразуем s1 в число x
2.3. Добавим число к сумме. 
2.4. Удалим эти символы из строки вместе со знаком «+».

3. Вывод результата.

IV. Описание переменных: st, s1, – string, x, s – int. 

Пример 9.20. В таблице приведены команды для преобразования.

Команда

Описание

stoi

stoll

Функции преобразуют строковое представление целого числа s к числовому значению типа int или long long

stoul stoull

Функции преобразуют строковое представление целого числа s к беззнаковому числовому значению типа unsigned int  или unsigned long long

stof,

stod,

stold

Функции преобразуют строковое представление вещественного числа s к числовому значению типа floa, doule или long double

to_string

Функция преобразует число  к строковому представлению

Функции преобразования строковых величин типа string в числовые появились только в 11 стандарте C++. Однако в Code:: Bloks они поддерживаются только с 14-й версии стандарта. Для подключения компилятора с поддержкой этого стандарта необходимо выполнить команду Settings → Compiler…

Пример 9.21.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string st;

  cout<<"Stroka"<<endl;

  getline(cin, st);

  int n = st.length();

  int s = 0;

  int k = n;

  for (int i = 0; i < n; i++)

  {

    if (st[i] >= '0' && st[i] <= '9'){

      string z;

      z = st[i];

      s += stoi(z);

    }

    else {

      k = i;

      break;

    }

  }

  if (< n)

    cout << "ne chislo" << endl;

  else

    cout << "summa = " << s << endl;

  return 0;

}

 VI. Тестирование.

Проверку того, является ли символ цифрой, можно выполнить несколькими разными способами. Это можно сделать аналогично тому, как в примере 9.14 выполнялась проверка знаков препинания. Для этого нужно создать строку и перечислить в ней все цифры — z = ''0123456789'';

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

   int z = st[i] - '0';

   s += z;

В данном случае переменная z — разница  кодов текущей цифры и цифры 0. Поскольку цифры в таблице расположены по порядку, то получим числовое значение символа цифры.

Пример 9.22.

V. Программа:

#include <iostream>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

int main()

{

  string st, s1;

  cout<<"Stroka"<<endl;

  getline(cin, st);

  int s = 0;

  while (!st.empty())

  {

    int n = st.find('+');

    if (!= -1){

      s1 = st.substr(0,n);

      st.erase(0, n + 1);

    }

    else

    {

      s1 = st;

      st.clear();

    }

    int x = stoi(s1);

    s += x;

  }

  cout << "summa = " << s << endl;

  return 0;

}

 VI. Тестирование.

Вопросы к параграфу

1. Как описываются строковые переменные?

2. Из чего состоят строки?

3. Какие операции возможны над строками?

4. Как сравниваются строки?

5. Что является результатом сложения двух строк?

6. Что такое длина строки? С помощью какой функции можно найти длину строки?

7. Какие функции используются для определения позиции подстроки в строке?

8. Как скопировать символы из одной строки в другую?

9. Какая функция используется для удаления символов из строки?

10. Какая функция предназначена для вставки символов в строку?

Упражнения

    

1. Напишите программу для решения задачи. Пользователь вводит свою фамилию, класс и учебное заведение, программа должна вывести сообщение «Учащийся … учится в … классе ГУО "…"». Вместо многоточия должны быть выведены соответствующие значения.

2. Измените программу из примера 9.8 так, чтобы на экран выводился символ введенного слова, стоящий посередине. Выведите позиции всех символов, совпадающих со средним символом слова.

3. Измените программу из примера 9.8 так, чтобы строчные и заглавные буквы анализировались программой одинаково (например, для слова «Анна» ответ должен быть следующим: «последний символ — а, символ встретился на месте 1»).

4. Даны два слова. Верно ли, что одно из слов начинается на ту же букву, на которую заканчивается другое? (Первая буква одного из слов может быть заглавной). Если да, то вывести букву, иначе соответствующее сообщение. *Если ответ «верно», указать, принадлежат ли буквы одному регистру.

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

1. Напишите программу, которая определит количество предложений в тексте. Предложение заканчивается одним из трех символов: «.», «?», «!». Предполагается, что в тексте есть хотя бы одно предложение (см. пример 9.12).
2. Напишите программу, которая определит количество слов в тексте, если между любыми двумя словами может быть более одного пробела. Предполагается, что в тексте есть хотя бы одно слово.
3. Напишите программу, которая определит, каких букв в строке с русским текстом больше: «о» или «O».
4. Напишите программу, которая определит, какой процент составляют буквы 'a' во введенном тексте.
5. Напишите программу, которая определит, сколько слов в тексте начинается на букву «а».
6*. Напишите программу, которая определит, какой процент слов в тексте начинается на букву «к». (Слово может начинаться как с прописной, так и со строчной буквы.)

6. Дан текст. Напишите программу, которая проверит, правильно ли в нем расставлены круглые скобки. Если нет, то вывести соответствующее сообщение: открывающихся скобок больше (меньше), чем закрывающихся, закрывающаяся скобка раньше открывающейся скобки.

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

1. Заменить в заданном тексте каждую букву «a» символом «*».
2. Заменить в заданном тексте каждую цифру символом «?».
3. Заменить в заданном тексте из латинских букв все вхождения «x» на «ks».
4. Заменить в заданном тексте из латинских букв все вхождения «ing» на «ed».
5. Заменить все слова А1 на слова А2 (слова в тексте разделены пробелами, слова А1 и А2 вводятся).

8. Напишите программу, которая удалит из текста некоторые символы.

1. Удалить из текста все гласные буквы.
2. Удалить из текста все знаки «+», непосредственно за которыми стоит не цифра.

9. Напишите программу, которая вставит в текст некоторые символы.

1. После каждой латинской буквы «q» добавить букву «u». 
2. После каждого из перечисленных знаков препинания («.», «,», «:», «;») вставить пробел, если его там нет.

10. Выполните для примера 9.19.

1. Измените функцию CheckPalindrom так, чтобы слова, которые начинаются на заглавную букву, тоже считались палиндромами, например: «Анна», «Алла».
2. Добавьте в программу подсчет количества выведенных палиндромов.

11*. Фразы-палиндромы читаются одинаково слева направо и справа налево без учета пробелов и знаков препинания. Например: «Кулинар, храни лук» или «А роза упала на лапу Азора». Напишите программу, которая определит, является ли фраза палиндромом.

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

13. Измените программу из упражнения 12 так, чтобы проверялась делимость на 2, 3, 5, 6, 8, 12 (используйте соответствующие признаки делимости).

14. Дан текст. Напишите программу, которая проверит, может ли быть этот текст записью вещественного числа.

15. Напишите программу для решения задачи. Строка представляет собой запись следующего вида: «а ± b ±  с ±…». Найти значение выражения. Вместо знака «±» может быть знак «+» или знак «-». Числа являются целыми (тип int).

16. Напишите программу для решения задачи. Строка представляет собой запись следующего вида: «(a + b)c». Выделить из записи числа и найти значение выражения. Числа, входящие в выражение, являются целыми (тип int).

17*. Строка представляет собой запись следующего вида: «число circled times число ± число circled times число ± … ± число circled times число», где вместо знака circled times может быть * или /, а вместо знака «±» — знаки «+» или «-». Написать программу, которая выделит из записи строки числа и найдет значение выражения. Значения чисел помещаются в тип double.

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