Строки

Строки

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

Тип str

Для взаимодействия со строками в языке есть встроенный тип str. Его литералом являются одиночные ' или двойные кавычки ". Символы (код), заключенный между кавычками будет восприниматься Python, как строка:

>>> s1 = 'Привет! Я строка!'
>>> s2 = "Привет! Я тоже строка!"
>>> type(s1)
<class 'str'>
>>> type(s2)
<class 'str'>

Строка может быть пустой: '' или "".

Чтобы воспользоваться кавычками внутри строки, есть два пути:

  1. Воспользоваться в качестве литерала одним видом кавычек, а внутри строки пользоваться вторым видом кавычек;
  2. Экранировать кавычки внутри строки с помощью символа экранирования (escape character) \, он же называется обратной косой чертой.

Например:

>>> s4 = '\'Я внутри одинарных кавычек\', а "я внутри двойных"'
>>> s4
'\'Я внутри одинарных кавычек\', а "я внутри двойных"'
>>> print(s4)
'Я внутри одинарных кавычек', а "я внутри двойных"

Здесь в качестве литерала взяты одинарные кавычки, для первой части фразы используется экранирование, а для второй двойные.

Более того, для удобного написания многострочной строки (простите), можно воспользоваться тройными одинарными или тройными двойными кавычками, причём внутри такой строки экранирование не понадобится:

>>> multiline_str = '''Я первая строка
... I'm the second line
... А я третья!'''
>>> multiline_str
"Я первая строка\nI'm the second line\nА я третья!"
>>> print(multiline_str)
Я первая строка
I'm the second line
А я третья!

Заметьте, что во второй строке экранирование кавычки не понадобилось (I'm).

Также, вы могли заметить, что при вызове в интерактивном режиме строка отображается в виде, в котором представлена в программе, и только при печати print() отображается ожидаемо. В случае печати чисел это было не заметно.

Напоследок, небольшой список часто используемых экранированных последовательностей (escape sequence):

  • символ новой строки \n
  • табуляция \t, с помощью табуляции можно получать удобные для чтения таблицы
  • кавычки \', \"
  • обратная косая \\

Доступ к символам и срезы строк

Так же, как и список, строка это упорядоченная последовательность. Если список это последовательность объектов произвольного типа, то строка это последовательность символов.

Можно узнать длину строки, получить символ на определённой позиции и даже получить срез строки:

>>> s = "Hello, World!"
>>> len(s)
13
>>> s[0]
'H'
>>> s[7:]
'World!'
>>> s[::2]
'Hlo ol!'

Конкатенация и неизменяемость строк

Простейшая операция над двумя строками это конкатенация - приписывание второй строки в конец первой:

>>> str_1 = "ABC"
>>> str_2 = "def"
>>> str_1 + str_2
'ABCdef'
>>> str_2 + str_1
'defABC'

Более того, с помощью символа умножения * можно конкатенировать строку с самой собой несколько раз:

>>> str_1
'ABC'
>>> str_1 * 10
'ABCABCABCABCABCABCABCABCABCABC'
>>> 5 * str_1
'ABCABCABCABCABC'
>>> str_1
'ABC'
>>> str_2
'def'
>>> (str_1 + str_2) * 5
'ABCdefABCdefABCdefABCdefABCdef'

Строки являются неизменяемым типом в Python. При попытке изменения символа на какой-то позиции произойдёт ошибка:

>>> s = 'ваза'
>>> s[0] = 'б'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

На самом деле, в примерах по конкатенации Python создавал новые объекты строк. Даже операция инкрементирования создаёт новую строку, в чём можно убедиться, узнав их идентификатор (в данном случае это равносильно адресу в памяти):

>>> s = 'a'
>>> id(s)
4465232176
>>> s += 'b'
>>> s
'ab'
>>> id(s)
4466564720

Некоторые методы строк

У строк в Python огромное количество методов. Не верите? Вот они:

str.capitalize()
str.casefold()
str.center(width[, fillchar])
str.count(sub[, start[, end]])
str.encode(encoding="utf-8", errors="strict")
str.endswith(suffix[, start[, end]])
str.expandtabs(tabsize=8)
str.find(sub[, start[, end]])
str.format(*args, **kwargs)
str.format_map(mapping)
str.index(sub[, start[, end]])
str.isalnum()
str.isalpha()
str.isascii()
str.isdecimal()
str.isdigit()
str.isidentifier()
str.islower()
str.isnumeric()
str.isprintable()
str.isspace()
str.istitle()
str.isupper()
str.join(iterable)
str.ljust(width[, fillchar])
str.lower()
str.lstrip([chars])
static str.maketrans(x[, y[, z]])
str.partition(sep)
str.replace(old, new[, count])
str.rfind(sub[, start[, end]])
str.rindex(sub[, start[, end]])
str.rjust(width[, fillchar])
str.rpartition(sep)
str.rsplit(sep=None, maxsplit=-1)
str.rstrip([chars])
str.split(sep=None, maxsplit=-1)
str.splitlines([keepends])
str.startswith(prefix[, start[, end]])
str.strip([chars])
str.swapcase()
str.title()
str.translate(table)
str.upper()
str.zfill(width)

Мы разберём только некоторые из них (для остальных есть help(str.method_name) :-)

Поиск

Метод str.find ищет подстроку в строке и возвращает индекс начала найденной подстроки. Если вхождение не найдено, вернётся -1:

>>> s = 'Hello, World!'
>>> s.find('World')
7
>>> s[7]
'W'
>>> s.find('Universe')
-1

Этот метод имеет два необязательных аргумента start и end. Если их указать, то поиск будет осуществляться в срезе строки s[start:end]:

>>> s
'Hello, World!'
>>> s.find('o')
4
>>> s[3:6]
'lo,'
>>> s.find('o', 7)
8
>>> s[7:10]
'Wor'

И, как видно, str.find осуществляет поиск первого вхождения подстроки, начиная слева.

Чтобы осуществить поиск подстроки, начиная справа (т.е. с конца) строки, можно воспользоваться методом str.rfind. Сравните:

>>> s
'Hello, World!'
>>> s.rfind('o')
8
>>> s.find('o')
4

Метод str.rfind имеет тот же интерфейс, что и str.find: он имеет два необязательных аргумента, чтобы задать диапазон поиска и возвращает -1, если подстрока не найдена.

Подсчёт

Методом str.count можно подсчитать количество вхождений подстроки в строку:

>>> s = 'Пингвины не любят окна.'
>>> s.count('а')
1
>>> s.count('ин')
2
>>> s.count('яблоки')
0

Диапазон поиска можно указать так же, как в str.find.

Замена

Для замены подстроки в строке существует метод str.replace:

>>> src = 'Пингвины не любят окна.'
>>> replaced = src.replace('Пингвины', 'Даже окна')
>>> src
'Пингвины не любят окна.'
>>> replaced
'Даже окна не любят окна.'

Так как строки в Python неизменяемые, то str.replace на базе исходной строки создает и возвращает новую.

У этого метода есть дополнительный параметр - количество производимых замен. Если этот параметр выставлен в -1 (значение по умолчанию), то произойдёт замена всех вхождений.

>>> s = 'aaaaa'
>>> s.replace('a', 'b')
'bbbbb'
>>> s.replace('a', 'b', 3)
'bbbaa'

Разбиение и объединение

По существу, вы уже знакомы с этими операциями и применяли их.

Можно разбивать строку на основе подстроки с помощью str.split. Результатом этой операции является список. Например, может стоять задача по разбиению предложения на слова:

>>> sentence = 'Пингвины не любят окна.'
>>> sentence.split()
['Пингвины', 'не', 'любят', 'окна.']
>>> sentence2 = 'вставка, выбор, пузырёк, подсчёт, Хоар, слияние'
>>> sentence2.split(', ')
['вставка', 'выбор', 'пузырёк', 'подсчёт', 'Хоар', 'слияние']

В первом случае в качестве подстроки для разбиения используется значение по умолчанию: разбиение по символам, обозначающих пустое пространство (пробелы, табуляция, перенос строки). Во втором случае разбиение задано явно - по подстроке ', '.

Больше примеров:

>>> sentence3 = 'вставка -- выбор -- пузырёк -- подсчёт -- Хоар -- слияние'
>>> sentence3.split()
['вставка', '--', 'выбор', '--', 'пузырёк', '--', 'подсчёт', '--', 'Хоар', '--', 'слияние']
>>> sentence3.split('--')
['вставка ', ' выбор ', ' пузырёк ', ' подсчёт ', ' Хоар ', ' слияние']
>>> sentence3.split(' -- ')
['вставка', 'выбор', 'пузырёк', 'подсчёт', 'Хоар', 'слияние']

У str.split есть ещё один необязательный аргумент - количество разбиений.

Итак, str.split разбивает строку по подстроке и возвращает список строк. Обратная операция это объединение массива строк в одну строку, она осуществляется с помощью str.join:

>>> sentence3 = 'вставка -- выбор -- пузырёк -- подсчёт -- Хоар -- слияние'
>>> sort_algs = sentence3.split(' -- ')
>>> sort_algs
['вставка', 'выбор', 'пузырёк', 'подсчёт', 'Хоар', 'слияние']
>>> ''.join(sort_algs)
'вставкавыборпузырёкподсчётХоарслияние'
>>> ' '.join(sort_algs)
'вставка выбор пузырёк подсчёт Хоар слияние'
>>> ' + '.join(sort_algs)
'вставка + выбор + пузырёк + подсчёт + Хоар + слияние'

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

>>> ' '.join(range(10))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected str instance, int found
>>> ' '.join(map(str, range(10)))
'0 1 2 3 4 5 6 7 8 9'