Строки и Символы - Язык программирования C++ для спортивного программирования
Неделя 5Строки и Символы, Обработка текста, Обработка ввода
Строки и Символы
char — это число: коды символов, int(c) и char(x), номер буквы, другой регистр, значение цифры; помощники из cctype; чтение по одному символу; строка как ряд char — s[i], size, изменение символа; чтение слова или целой строки; склеивание через + и +=; сравнение строк в словарном порядке и огромные числа в виде текста; stoi, stoll, stod и to_string.
Теория
Урок 1 из 10
15 мин чтения
Вопросов: 6
С первой недели char и string были типами, которые читают и печатают:
char c; хранит один символ, string s; — слово. Но в обоих гораздо больше.
char на самом деле число, поэтому буквы можно считать, сдвигать и
сравнивать с помощью арифметики. А string на самом деле ряд char,
пронумерованный с 0, как ячейки вектора, — поэтому всё, что на неделе 4 делалось
с векторами, работает и с текстом.
Символ — это число
Каждый символ, который хранит компьютер, — буква, цифра, пробел, запятая —
хранится как число, его код. Коды берутся из таблицы ASCII, и буквы и
цифры стоят в ней по порядку, без пропусков:
Символы
Коды
' ' (пробел)
32
'0''1' … '9'
48 49 … 57
'A''B' … 'Z'
65 66 … 90
'a''b' … 'z'
97 98 … 122
char хранит код, а cout показывает char как символ. Чтобы получить код
вместо символа или символ вместо кода, преобразуйте тип:
Символ в одинарных кавычках и число — не одно и то же: '7' — это символ
с кодом 55, а 7 — число семь.
Арифметика с символами
дальше
Практика: Символы
Коды и буквы, арифметика с буквами и чтение по одному символу.
Раз буквы стоят по порядку, арифметика кодов — это арифметика алфавита:
Вопрос
Выражение
Пример
Какая это буква, считая с 0?
c - 'a'
'd' - 'a' равно 3
Буква на позиции k (с 0)
char('a' + k)
char('a' + 2) — это 'c'
Следующая буква
char(c + 1)
после 'g' идёт 'h'
Как далеко две буквы друг от друга?
abs(a - b)
'a' и 'e': 4
Та же буква заглавной
char(c - 32)
'g' → 'G'
Та же буква строчной
char(c + 32)
'G' → 'g'
Значение символа-цифры
c - '0'
'7' - '0' равно 7
Символ цифры
char('0' + d)
char('0' + 4) — это '4'
За двумя вещами нужно следить:
Арифметика с char даёт int.cout << 'a' + 2; печатает 99, а не c.
Оберните результат в char(…), чтобы напечатать символ, — или сначала
сохраните его в переменную char: char next = c + 1; хранит символ.
min, max и сравнения работают с символами по их кодам: min('d', 'b') —
это 'b', та, что раньше в алфавите. Но заглавная буква идёт раньше любой
строчной: 'Z' (90) меньше 'a' (97).
char может быть и переменной цикла — этот цикл печатает алфавит:
Чтение по одному символу
cin >> c для char c читает ровно один символ (пропустив перед ним пробелы
и переводы строки). Поэтому короткий код не нужно разбивать — читайте его
посимвольно:
У шкафчиков в школе коды вроде C7: заглавная буква — ряд (A — ряд 1), а
цифра — полка. Выведите ряд и полку числами.
Ввод
Вывод
Так же читается первая цифра числа из ста цифр — слишком длинного для любого
целого типа: прочитайте один char, и это и есть первая цифра.
Полезные функции для символов
В C++ есть готовые вопросы и преобразования для одного символа:
Функция
Даёт
isdigit(c)
истину для '0' … '9'
isalpha(c)
истину для буквы, заглавной или строчной
isupper(c) / islower(c)
истину для заглавной / строчной буквы
toupper(c) / tolower(c)
букву в другом регистре; любой другой символ без изменений
Они избавляют от того, чтобы снова и снова писать c >= 'a' && c <= 'z', а
toupper не трогает цифры и знаки, которые c - 32 испортил бы. Одна ловушка:
toupper и tolower возвращают код, то есть int, поэтому
cout << toupper('a'); печатает 65. Сохраните результат в char или оберните
его: cout << char(toupper('a')); печатает A. (Некоторые задачи просят сделать
это «вручную», через - 32: тогда делайте именно так.)
Строка — это ряд символов
s — это пять символов подряд с индексами от 0, в точности как вектор: s[0] —
это 'L', s[4] — это 'n', а s.size() равно 5. Каждый s[i] — это char,
поэтому его можно читать, сравнивать и менять:
Строка — это ряд символов
C++
1#include <bits/stdc++.h>
2using namespace std;
3
4int main() {
5 ios_base::sync_with_stdio(false);
6 cin.tie(NULL);
7
8 string s = "Lemon";
9 int n = s.size();
10 char first = s[0];
11 s[0] = 'M';
12 s[2] = 'l';
13 s += 's';
14 cout << s << " " << s.size() << " " << first << "\n";
15 return 0;
16}
Ряд из 5 символов
строка 8
В s лежат L e m o n в ячейках s[0] … s[4] — каждая ячейка это char, в одинарных кавычках.
s5 ячеек
'L'
'e'
'm'
'o'
'n'
0
1
2
3
4
n—first—
нажми пуск
1 / 7
Всё, что верно для индексов вектора, верно и здесь:
Индексы идут от 0 до s.size() - 1. Последний символ — это
s[s.size() - 1]; s[s.size()] уже за концом строки.
s.size() — беззнаковое число, поэтому s.size() - 1 для пустой строки —
огромное число, а не −1. Сначала положите длину в int —
int n = s.size(); — и считайте с n.
s += c; добавляет символ в конец (как push_back у вектора), а
string s = ""; — пустая строка, к которой можно дописывать символы.
Чтение слов и строк
cin >> s читает одно слово: пропускает пробелы и переводы строки, а затем
берёт символы до следующего пробела или перевода строки. Поэтому два слова — на
одной строке или на двух — читаются через cin >> s >> t;.
Чтобы прочитать всю строку целиком, с пробелами, используйте getline:
Во входных файлах, сделанных в Windows, каждая строка заканчивается двумя
символами: \r, а потом \n. cin >> s считает \r пробелом и никогда его не
сохраняет, а getline останавливается на \n и оставляет \r в конце строки.
Если дальше вы считаете символы строки, сначала уберите его:
Подробно о чтении — в уроке Обработка ввода.
Склеивание строк
+ склеивает две строки, а += дописывает в конец одной:
cout << a << b; печатает две строки, ничего не ставя между ними, —
автоматического пробела нет. Если в примере из условия два слова склеены, значит, так и нужно;
если там пробел — напечатайте пробел.
Сравнение строк
== и != сравнивают строки целиком, символ за символом: "cat" == "Cat"
ложно, потому что у 'c' и 'C' разные коды.
< и > расставляют строки в словарном порядке: сравниваются первые
символы, если они равны — вторые, и так далее; решает первое различие, по
кодам. Если одна строка закончилась раньше, более короткая идёт первой.
Сравнение
Истинно?
Почему
"apple" < "banana"
да
'a' (97) раньше 'b' (98)
"Mia" < "Max"
нет
'M' = 'M', затем 'i' (105) после 'a' (97)
"Ann" < "Anna"
да
"Ann" заканчивается раньше
"Zoe" < "adam"
да
любая заглавная раньше любой строчной
"10" < "9"
да
как текст: '1' (49) раньше '9' (57)
Последняя строка важна: числа, хранящиеся текстом, не сравниваются как
числа. Чтобы сравнить два целых числа, записанных строками, — например, числа
из ста цифр, которые не вмещает ни один тип, — сначала сравните их длины:
больше цифр — больше число. Только когда длины равны, словарный порядок даёт
верный ответ, потому что тогда цифры стоят на одних и тех же местах.
Даны два очень длинных целых числа (без ведущих нулей). Выведите большее.
Ввод
Вывод
a.size() > b.size() сравнивает длины, a > b — текст. (x ? y : z означает
«y, если x истинно, иначе z» — короткий if, который даёт значение.)
Телефон сортирует контакты именно в этом порядке. Поставьте каждый новый контакт
туда, куда его отправляет <:
Куда встанет контакт?попробуй!
Строки и числа
Текст, похожий на число, всё равно остаётся текстом: + для двух строк с
"15" и "27" склеивает их в "1527". Чтобы выполнять арифметику,
преобразуйте текст в число; чтобы собрать текст из числа — наоборот:
Функция
Превращает
Во что
stoi(s)
"250"
int 250
stoll(s)
"9876543210123"
long long
stod(s)
"3.14"
double 3.14
to_string(x)
25
строку "25"
to_string от double всегда пишет шесть цифр после точки:
to_string(3.14) — это "3.140000". Чтобы напечатать вещественное число с
нужным числом знаков, используйте fixed << setprecision(k) с первой недели.
Склеивание и преобразование вместе дают удобный приём. При
string a = "30", b = "4"; два числа, записанные рядом в одном и в другом
порядке, — это stoi(a + b) = 304 и stoi(b + a) = 430. (Два текста в
кавычках напрямую склеить нельзя: "30" + "4" не компилируется — хотя бы с
одной стороны + должна стоять string, а не текст в кавычках.)
Проверьте себя
А вы знали?
ASCII опубликовали в 1963 году (строчные буквы появились в нём в 1967-м), и
буквы в нём расставили не случайно: 'A' — это 65 = 64 + 1, а 'a' —
97 = 64 + 32 + 1. Заглавная буква и её строчная отличаются ровно одним
двоичным разрядом — тем, что означает 32, — поэтому для
машин того времени смена регистра была переключением одного бита. Цифры
расставили так же: '0' … '9' — это 48 … 57, и последние четыре двоичные
цифры каждого кода — значение самой цифры.
char c = 'a';cout << int(c)<< "\n"; // 97: код 'a'cout << char(98)<< "\n"; // b: символ с кодом 98
проверь себя1 балл
Чему равно ('7' - '0') * 10 + ('3' - '0')?
Войдите, чтобы ответить и сохранить прогресс.Войти
проверь себя1 балл
Ввод — строка New York City. Что напечатает этот код?
Войдите, чтобы ответить и сохранить прогресс.Войти
проверь себя1 балл
Что напечатает этот код?
Войдите, чтобы ответить и сохранить прогресс.Войти
проверь себя1 балл
Что напечатает этот код?
Выберите один ответ
Войдите, чтобы ответить и сохранить прогресс.Войти
проверь себя1 балл
Что напечатает cout << tolower('Q');?
Выберите один ответ
Войдите, чтобы ответить и сохранить прогресс.Войти
проверь себя1 балл
Какое из этих сравнений строк истинно?
Выберите один ответ
Войдите, чтобы ответить и сохранить прогресс.Войти
C7
row 3, shelf 7
98765432109876543210
123456789012345678901
123456789012345678901
for(char c = 'a'; c <= 'z'; c++){ cout << c;}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); char row, shelf; cin >> row >> shelf; // "C7": по одному символу int r = row - 'A' + 1; // 'A' — ряд 1, 'B' — ряд 2, ... int s = shelf - '0'; // цифра '7' становится числом 7 cout << "row "<< r << ", shelf "<< s << "\n"; return 0;}
string s = "Lemon";
string line;getline(cin, line); // "Hello, World 42!" — целиком
string first = "Aziz", last = "Karimov";string tag = last + ", " + first; // "Karimov, Aziz"tag += '!'; // "Karimov, Aziz!"
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); string a, b; // слишком длинные для long long cin >> a >> b; string big; if(a.size() != b.size()){ big =(a.size()> b.size()) ? a : b; // больше цифр — больше число} else{ big =(a > b) ? a : b; // длина одна: сравниваем как слова} cout << big << "\n"; return 0;}
string a = "15", b = "27";cout << a + b << "\n"; // 1527: склееныcout << stoi(a) + stoi(b)<< "\n"; // 42: сложеныstring msg = "I am " + to_string(15) + " years old.";
string s;cin >> s;cout << s.size();
string a = "7", b = "40";cout << stoi(b + a) - stoi(a + b);