Строки
Индексы, срезы, перебор букв, count, replace, split и маски. Строки нужны в каждом третьем номере, и даже числа на ЕГЭ часто удобнее превратить в строку.
- 1Индексы
- 2Срезы
- 3Перебор строки
- 4count, replace, in
- 5split и join
- 6Маски: fnmatch
- 7Сломай код
- 8Где пригодится на ЕГЭ
Индексы
Строка это цепочка символов, и у каждого символа есть номер, индекс. Нумерация начинается с нуля.
s = 'ПИТОН' print(s[0]) # первая буква print(s[1]) # вторая print(len(s)) # длина строки print(s[len(s) - 1]) # последняя
Последний символ стоит под номером len(s) - 1, потому что счёт с нуля. Писать так каждый раз неудобно, поэтому в Python есть отрицательные индексы: они считают с конца.
s = 'ПИТОН' print(s[-1]) # последняя print(s[-2]) # предпоследняя
| Буква | П | И | Т | О | Н |
|---|---|---|---|---|---|
| индекс | 0 | 1 | 2 | 3 | 4 |
| с конца | −5 | −4 | −3 | −2 | −1 |
Срезы
Срез вырезает из строки кусок: s[a:b] берёт символы с индекса a до b, не включая b. Это то же правило, что у range.
s = 'ИНФОРМАТИКА' print(s[0:4]) # с 0 по 3 print(s[:4]) # то же самое: начало можно не писать print(s[7:]) # с 7 до конца print(s[-3:]) # последние три символа
Третье число в срезе это шаг, как в range. Шаг −1 идёт с конца, то есть переворачивает строку:
s = 'ИНФОРМАТИКА' print(s[::2]) # каждая вторая буква print(s[::-1]) # строка задом наперёд
Переворот нужен очень часто, например, чтобы проверить палиндром: строку, которая читается одинаково в обе стороны.
s = input() if s == s[::-1]: print('палиндром') else: print('не палиндром')
Сколько чисел от 1 до 9999 являются палиндромами? Например, 7, 44, 121 и 3003.
Перебор строки
for умеет перебирать не только range, но и строку: переменная по очереди становится каждой буквой.
k = 0 for c in 'ИНФОРМАТИКА': if c in 'АЕИОУЫЭЮЯ': # c гласная? k += 1 print('Гласных:', k)
Когда нужно смотреть на соседние символы, перебирают не буквы, а индексы. Тогда текущая буква это s[i], а следующая s[i + 1]:
s = 'АББВВВГ' k = 0 for i in range(len(s) - 1): # до предпоследней, иначе s[i + 1] выйдет за край if s[i] == s[i + 1]: k += 1 print('Пар одинаковых соседей:', k)
Почему range(len(s) - 1)? У последней буквы соседа справа нет. Если дойти до неё, s[i + 1] выйдет за конец строки, и будет ошибка.
Самая длинная цепочка
Это основа №24. Идём по строке и держим длину текущей цепочки: если буква такая же, как предыдущая, цепочка растёт, иначе начинается заново.
s = 'АББВВВГВВ' cur = 1 # длина текущей цепочки best = 1 # самая длинная, что видели for i in range(1, len(s)): if s[i] == s[i - 1]: cur += 1 else: cur = 1 best = max(best, cur) print(best)
count, replace, in
Три инструмента, без которых не обходится №8 и №12.
| Запись | Что делает |
|---|---|
s.count('А') | сколько раз встречается |
'АБ' in s | есть ли такой кусок в строке |
s.replace('А', 'Б') | новая строка, где все А заменены на Б |
s.replace('А', 'Б', 1) | то же, но заменить только первое А |
s.upper(), s.lower() | все буквы большие или маленькие |
s = 'Мама мыла раму' print(s.count('а')) print('мыла' in s) print(s.replace('а', 'о')) print(s.lower().count('м')) # М и м одним счётом
s.replace(...) не меняет s, а возвращает новую строку. Чтобы замена сохранилась, пиши s = s.replace(...). Так же нельзя поменять одну букву через s[0] = 'Х', будет ошибка.
Замены в цикле
Задача №12 устроена так: пока в строке есть какой-то кусок, заменяем его. Это while и replace с единицей в конце, чтобы менять по одному куску за шаг:
s = '1' * 10 # строка из десяти единиц while '11' in s: s = s.replace('11', '2', 1) # первое вхождение 11 меняем на 2 print(s)
Строка из 95 единиц. Пока в ней есть 22 или 111: если есть 22, первое такое заменяем на 1, иначе первое 111 заменяем на 2. Чему равна сумма цифр получившейся строки?
split и join
split режет строку на части. Без аргумента режет по пробелам, а с аргументом по любому символу:
print('12 7 30 5'.split()) print('192.168.0.1'.split('.'))
Получается список строк. Списки подробно будут в теме 6, пока достаточно знать, что по ним можно пройти циклом:
s = 0 for x in '12 7 30 5'.split(): s += int(x) # каждый кусок это строка, превращаем в число print(s)
join делает обратное: склеивает части в одну строку. Перед точкой пишут, чем склеивать:
parts = ['192', '168', '0', '1'] print('.'.join(parts)) print(''.join(parts))
''.join с пустыми кавычками ты уже видел в уроке №8: им склеивают буквы, которые выдаёт product.
Чему равна сумма чисел больше 10 в строке '12 7 30 5 18'?
Маски: fnmatch
В №25 бывают условия вида «число соответствует маске 12*4?5». В маске два особых символа:
?означает ровно одну любую цифру;*означает любую цепочку цифр, в том числе пустую.
Писать такую проверку руками сложно, но в Python она уже есть: функция fnmatch из модуля с тем же названием. Число превращаем в строку и проверяем:
from fnmatch import fnmatch print(fnmatch('1234', '12*4')) # * это '3' print(fnmatch('124', '12*4')) # * пустая, тоже подходит print(fnmatch('12345', '12*4')) # в конце 5, а не 4 print(fnmatch('1294', '12?4')) # ? это одна цифра
Пример: найдём все числа до 10 000, которые подходят под маску 1?2*5 и делятся на 25.
from fnmatch import fnmatch for n in range(25, 10000, 25): # сразу перебираем только кратные 25 if fnmatch(str(n), '1?2*5'): print(n)
Обрати внимание на range с шагом 25. Нам нужны только числа, кратные 25, так что перебираем только их. Это в 25 раз быстрее, чем проверять каждое число через n % 25 == 0.
Сколько чисел меньше 1 000 000 соответствуют маске 12*4 и делятся на 19?
Сломай код
IndexError: за краем строки
s = 'КОТ' print(s[3])
string index out of range: в строке из 3 букв индексы 0, 1, 2. Индекса 3 нет. Чаще всего это случается при проверке соседей s[i + 1] на последней букве.
TypeError: строку не поменять
s = 'КОТ' s[0] = 'Р'
'str' object does not support item assignment. Строку нельзя изменить по кусочку. Можно собрать новую: s = 'Р' + s[1:].
Тихая ошибка: replace без присваивания
s = 'АААБ' s.replace('А', 'Б') print(s)
Ничего не поменялось: новая строка получилась, но никуда не сохранилась. Нужно s = s.replace('А', 'Б').
Тихая ошибка: count не видит наложений
print('ААА'.count('АА'))
Кажется, что пар две (первая со второй, вторая с третьей), а count насчитал одну. Он считает вхождения, которые не накладываются друг на друга. Если наложения важны, перебирай индексы и проверяй s[i:i + 2] == 'АА'.
Где пригодится на ЕГЭ
| Номер | Что из темы |
|---|---|
| №8 | count, in, replace, проверки букв по индексу |
| №12 | while ... in s и replace(..., 1) |
| №24 | перебор строки, самая длинная цепочка, соседи |
| №25 | fnmatch для масок |
| №5 | двоичная запись это строка: срезы, count('1'), приписать цифру через + |
| №14 | подсчёт цифр в записи числа через count |
В №5 это выглядит так: двоичную запись числа (о ней в следующей теме) обрабатываем как обычную строку.
n = 13 b = bin(n)[2:] # двоичная запись: '1101' if b.count('1') % 2 == 0: b = b + '0' else: b = b + '1' print(b, int(b, 2)) # новая запись и её значение
Тут срез [2:], count и склейка +, всё из этой темы.
Код в блоках можно менять и запускать прямо в браузере.