pyth_05_str
Заметка 5. Текстовая строчка
курса Математический практикум по Питону.
Шокуров Антон В.
shokurov.anton.v@yandex.ru
http://машинноезрение.рф
Версия 0.11

Аннотация

Вводится базовы объект из Питона (Python): строчка (str). Показано как создавать, преобразовывать, искать подсроки и тому подобное.

Это предварительная версия! Любые замечания приветсвуются.

Не список, но похож

Текстовая строка, str

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

Введение

Создание

In [1]:
'текстовая строка' # Одинарные кавычки.
Out[1]:
'текстовая строка'
In [2]:
"можно и в двойных кавычках" # Теперь кавычки двойные.
# Но результат содержит одинарные.
Out[2]:
'можно и в двойных кавычках'
In [3]:
type("строка"), type('ещё одна') # Тип в любом случае будет строка -- str.
Out[3]:
(str, str)
In [4]:
s = 'некая строка' # Можно конечно её присвоить переменной.
In [5]:
# Длина строки, 
len(s) # т.е. количество символом в её представлении.
Out[5]:
12
In [6]:
# Напомню:
s + ' завершилась.'
Out[6]:
'некая строка завершилась.'
In [7]:
list('строка')
Out[7]:
['с', 'т', 'р', 'о', 'к', 'а']

Индекс

Индекс работает также как и для списка, list. Не будем подробно останавливаться. Строка текста тоже на самом деле может быть проиндексирована, т.е. можно считать букву по индексу.

In [8]:
"индекс"[1] # Считываем второй символ строки.
Out[8]:
'н'
In [9]:
s[4] # Тоже для переменной типа str.
Out[9]:
'я'
In [10]:
s[-1]
Out[10]:
'а'
In [11]:
# Даже такое.
s[1::2] # Результат тоже строка.
Out[11]:
'еа тоа'
In [12]:
# Поэтому можно опять взять индекс.
s[1::2][1] # Индекс от индекса.
Out[12]:
'а'

Но есть и существенные отличия. Например, строка неизменяемый объект, константный.

In [13]:
# Но присовить новое значение нельзя.
s[4] = 'a' # Присвоить новое значение нельзя.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-dd7bda6b0e30> in <module>
      1 # Но присовить новое значение нельзя.
----> 2 s[4] = 'a' # Присвоить новое значение нельзя.

TypeError: 'str' object does not support item assignment

Касательно равенства

Проверка на равенство по сути, т.е. как строчки в обычном поимании.

In [14]:
# По сути они равны.
'строка' == "строка"
Out[14]:
True
In [15]:
# А эти строки нет.
'строка 1' == "строка 2" # Строки не совпадают.
Out[15]:
False

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

In [16]:
# Экономия места благодаря константности строк.
id( 'строка' ) == id("строка") # Указатель на них один и тот же.
Out[16]:
True
In [17]:
# Например, схожая вещь для целых чисел.
id(6), id(3+3)
Out[17]:
(94872206474080, 94872206474080)
In [18]:
# Отдельные цифры тоже являются константными объектами.
6 = 7 # Нельзя присвоить 6 7. 
  File "<ipython-input-18-a407e5fc6203>", line 2
    6 = 7 # Нельзя присвоить 6 7.
                                  ^
SyntaxError: can't assign to literal

В сложных выражениях тоже будет работать.

In [19]:
['aa',['bb']] == ['aa', ['bb']]
Out[19]:
True
In [20]:
id( ['строка'] ) == id( ["строка"] )
Out[20]:
True

Сравнение нужно делать аккуратно.

In [21]:
["строка"], ["строка"][0] # Это понятно.
Out[21]:
(['строка'], 'строка')
In [22]:
# Сравним список со строкой и саму строку.
id( ['строка'] ) == id( ["строка"][0] )
# Конечно не равны.
Out[22]:
False

Печать строки

Красивая печать

In [23]:
# В фигурные скобки подставляются значения аргументов метода format.
"первое число {}, а теперь второе {}".format(4,2)
# первый аргумент вместо первой пары фигурных скобок, а второй вместо второй.
Out[23]:
'первое число 4, а теперь второе 2'

Конечно можно подставить любой объект. Например строчку.

In [24]:
"{} получила {} баллов за котрольную.".format('Маша',15)
Out[24]:
'Маша получила 15 баллов за котрольную.'

Можно указать порядковый номер аргумента в фигурных скобоках явно.

In [25]:
"или иначе, для начала второе число {1}, а теперь первое число {0}".format(4,2)
 # Позволяет менять порядок вывода аргументов.
Out[25]:
'или иначе, для начала второе число 2, а теперь первое число 4'
In [26]:
# Номер в фигурных скобрах можно повторять.
"или даже повторять {0}, {1}, {0}.".format(4, 2)
Out[26]:
'или даже повторять 4, 2, 4.'

Есть и более прдвинутый подход, где вместо номера указываем именной аргумент.

In [27]:
# Она подставляется автоматически в строке,
'sss {a} ff'.format(a=77) # т.е. там, где она заключена в фигурные скобки.
Out[27]:
'sss 77 ff'
In [28]:
a = 55 # Происвоем переменной.
'sss {a} ff'.format() # Имя a должно быть в format.
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-28-d2843b6f1e3b> in <module>
      1 a = 55 # Происвоем переменной.
----> 2 'sss {a} ff'.format() # Имя a должно быть в format.

KeyError: 'a'

Можно и саму переменную использовать в скобках (метода format тогда не будет использоваться ). Так, можно оперировать не порядковым номером, а именем переменной.

In [29]:
# Сначала присваиваем некой переменной значение.
a = 77 # Далее будем её использовать.
In [30]:
# Обращаю внимание на f перед строкой.
f'sss {a} ff'
Out[30]:
'sss 77 ff'
In [31]:
'sss {a} ff' # А вот что будет без f до строки.
Out[31]:
'sss {a} ff'

Выравнивание

In [32]:
# Центрируем текст.
s = 'center'.center(10) # В скобке указывается длина итоговой строки.
s
Out[32]:
'  center  '
In [33]:
len( s) # Длина строки.
Out[33]:
10
In [34]:
s[2:-2] # Проверим что это так.
Out[34]:
'center'
In [35]:
# Если трока больше требуемой величины.
s = 'center'.center(5) # то ничего не делается.
s
Out[35]:
'center'
In [36]:
len(s)
Out[36]:
6
In [37]:
# Пробелы превичной строки не учитываются,
l = 'q    '.center(8) # т.е. пробелы как обычные символы.
l
Out[37]:
' q      '
In [38]:
len(l)
Out[38]:
8
In [39]:
'Заявление'.center(80)
Out[39]:
'                                   Заявление                                    '
In [40]:
# Выравненная на левый край.
t = ' qq qq'.ljust(10)
t, len( t )
Out[40]:
(' qq qq    ', 10)
In [41]:
# Выравненная на правый край.
t = ' qq qq'.rjust(10)
t, len( t )
Out[41]:
('     qq qq', 10)
In [42]:
'Сидоров Иван Иванович'.rjust(80)
Out[42]:
'                                                           Сидоров Иван Иванович'

Различные проверки

Упорядочивание

In [43]:
'aaa' + 'bbbb' # Ещё наз напомню.
Out[43]:
'aaabbbb'

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

In [44]:
# Возвращает истину если первое слово ижет раньше второго  алфавитном порядке.
'Максим' < 'Дима' # Знак < вместо знака +.
Out[44]:
False
In [45]:
'Максим' < 'Федор'
Out[45]:
True
In [46]:
# Это можно рассматривать как единое целое,
'Максим' == 'Федор' # т.е. что операция == и < обе логические.
Out[46]:
False
In [47]:
# Возьмем, например, список имен.
names = ['Максим', 'Дима', 'Алексей', 'Олег']
names
Out[47]:
['Максим', 'Дима', 'Алексей', 'Олег']

Раз есть операция сравнения, то объекты списка можно упорядочить (отсортировать).

In [48]:
names.sort() # сортируем объекты в списке,
names # т.е. имена в списке.
Out[48]:
['Алексей', 'Дима', 'Максим', 'Олег']
In [49]:
misc = [4, 'Максим', 'Дима', 11]

Отсортировать объекты без определенной над объектами операции сравнения нельзя.

In [50]:
# В частности, ранородные: содержащие и цифры и строчки.
misc.sort()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-50-8265c7a41d41> in <module>
      1 # В частности, ранородные: содержащие и цифры и строчки.
----> 2 misc.sort()

TypeError: '<' not supported between instances of 'str' and 'int'
In [51]:
# Действительно. Нельзя сравнить.
3 < "Дима" # Пытаемся сравнить цифру и слово.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-51-79647bb5cad7> in <module>
      1 # Действительно. Нельзя сравнить.
----> 2 3 < "Дима" # Пытаемся сравнить цифру и слово.

TypeError: '<' not supported between instances of 'int' and 'str'
In [52]:
# Превратим цифры в строчки.
misc = ['4', 'Максим', 'Дима', '11']
misc.sort() # Теперь сработала сортировка.
misc # Она считает, что цифры идут раньше букв.
Out[52]:
['11', '4', 'Дима', 'Максим']

Интегральные базовые проверки

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

Если истинно утверждение для всех символов строки, то итоговы ответ истинен. Иначе ложь.

  • isalnum() Returns True if all characters in the string are alphanumeric
  • isalpha() Returns True if all characters in the string are in the alphabet
  • isdecimal() Returns True if all characters in the string are decimals
  • isdigit() Returns True if all characters in the string are digits
  • isidentifier() Returns True if the string is an identifier
  • islower() Returns True if all characters in the string are lower case
  • isnumeric() Returns True if all characters in the string are numeric
  • isprintable() Returns True if all characters in the string are printable
  • isspace() Returns True if all characters in the string are whitespaces
  • istitle() Returns True if the string follows the rules of a title
  • isupper() Returns True if all characters in the string are upper case
In [53]:
s = 'some text'
In [54]:
# Все ли символы явлются буковй?
s.isalpha() # Нет, не все. Пробел не буква.
Out[54]:
False
In [55]:
'fff'.isalpha(), 'f1ff'.isalpha() # Цифра (1) не буква.
Out[55]:
(True, False)
In [56]:
'   \t\n'.isspace(), ' a  \t\n'.isspace() # Буква (a) не пробел.
Out[56]:
(True, False)
In [57]:
# Истина тогда и только тогда когда строчка состоит из цифр.
'034'.isdigit()
Out[57]:
True
In [58]:
# Наличие одного не того символа достаточно для ложного ответа.
'5x88'.isdigit() # x  -- не число.
Out[58]:
False
In [59]:
'23'.isdecimal(), '23.5'.isdecimal()
Out[59]:
(True, False)
In [60]:
'23'.isnumeric(), '23.5'.isnumeric() # Сложно объяснить...
Out[60]:
(True, False)
In [61]:
# Проверка на строчный, верхний регистр символа.
'as'.islower(), 'AB4'.isupper(), 'bA'.isupper()
Out[61]:
(True, True, False)

Поиск

In [62]:
dat = '... Город: Москва'
In [63]:
# Поиск подстроки.
dat.find('Город: ',0,-1) #
Out[63]:
4
In [64]:
dat[4:]
Out[64]:
'Город: Москва'
In [65]:
dat.rfind('Город: ')
Out[65]:
4
In [66]:
'17:23:22'.find(':')
Out[66]:
2
In [67]:
'17:23:22'.rfind(':')
Out[67]:
5
In [68]:
# В случае, если строчка не найдена,
dat.find('Страна') # то возвращается -1.
Out[68]:
-1
In [69]:
dat.index('Страна') # Бросает исключение.
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-69-48644b652a12> in <module>
----> 1 dat.index('Страна') # Бросает исключение.

ValueError: substring not found
In [70]:
'17:23:22'.index(':'), '17:23:22'.rindex(':')
Out[70]:
(2, 5)
In [71]:
tt = 'с 12 час 23 мин по 14 час 31 мин'
In [72]:
# Извлекаем время. Пользуемся тем, что сначала идет время начальное, а потом конечное.
fr = tt.find('час') # from с
tl = tt.rfind('час') # till до
In [73]:
# Печатаем найденное время.
tt[fr-3:fr-1], tt[tl-3:tl-1]
Out[73]:
('12', '14')

Префикс и суфикс

Истина, если начинается с нужной строки.

In [74]:
'aa'.startswith('a')
Out[74]:
True
In [75]:
'abcde'.startswith('bc')
Out[75]:
False
In [76]:
'abcde'.startswith('bc', 1) # можно указать номер символа с которого начинать сравнение.
Out[76]:
True
In [77]:
'часов'.startswith('час'), 'час'.startswith('час'), 'час'.startswith('часов')
Out[77]:
(True, True, False)

Истина, если завершается нужной строкой.

In [78]:
'sdefgh'.endswith('gh')
Out[78]:
True
In [79]:
'asdfg'.endswith('df')
Out[79]:
False
In [80]:
'asdfg'.endswith('df', 0, -1)
Out[80]:
True
In [81]:
'12 часов'.endswith('часов'), '12 минут'.endswith('часов')
Out[81]:
(True, False)

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

Чистка пробелов

In [82]:
s = '  q  q     '
In [83]:
# Убираем лишние 'пробелы' в начале и конце строки.
s.strip()
Out[83]:
'q  q'
In [84]:
# Убераем пробелы только с одного из концов строки.
s.lstrip(), s.rstrip()
Out[84]:
('q  q     ', '  q  q')

Разбиение на подстроки и объединение

Иногда бывает нужным разбить строчку по пробелам.

In [85]:
# Разбиение по пробелу.
'Маша Катя Лена'.split(' ') # rsplit splitlines
Out[85]:
['Маша', 'Катя', 'Лена']
In [86]:
# На самом деле можно и по другому символу.
'Маша; Катя; Лена'.split('; ') # '; ' разделитель из двух символов.
Out[86]:
['Маша', 'Катя', 'Лена']
In [87]:
# По одному пробелу.
'Маша Катя  Лена '.split(' ') # В списке появилась пустая строка.
Out[87]:
['Маша', 'Катя', '', 'Лена', '']

А бывает, что нужно наоборот объеденить список строк. Между объединяемыми строками будем вставлена нужная строка.

In [88]:
names
Out[88]:
['Алексей', 'Дима', 'Максим', 'Олег']
In [89]:
# Объединяем список строчек посредством строки.
', '.join(names) # В данном случае ', '
Out[89]:
'Алексей, Дима, Максим, Олег'
In [90]:
', '.join(names) + '.' # Добавим и концевую точку.
Out[90]:
'Алексей, Дима, Максим, Олег.'
In [91]:
# Совсем педантично.
', '.join(names[:-1]) + ' и ' + names[-1] + '.'
Out[91]:
'Алексей, Дима, Максим и Олег.'

Отсечение

In [92]:
'a ggg ggg'.partition(' ') #rpartition
Out[92]:
('a', ' ', 'ggg ggg')
In [93]:
tt
Out[93]:
'с 12 час 23 мин по 14 час 31 мин'
In [94]:
ss = tt.partition('по')
ss
Out[94]:
('с 12 час 23 мин ', 'по', ' 14 час 31 мин')
In [95]:
# Тогда получится, что
ss[0] # это время с
Out[95]:
'с 12 час 23 мин '
In [96]:
ss[0].startswith('с ')
Out[96]:
True
In [97]:
ss[2] # это время по.
Out[97]:
' 14 час 31 мин'

Преобразования

Данные методы выполняют преобразование строчки согласно определенному правилу.

  • capitalize() -- Заглавная буква в начале предложения.
  • title() -- Заглавие: первая буква каждого слова преобразуется в заглавную.
  • lower() -- Все буквы к строчным.
  • upper() -- Каждая буква делается заглавной.
  • swapcase() -- Регистр меняется на противоположный.
  • casefold() -- Нормализация букв.
In [98]:
'цифровая обработка изображений'.capitalize()
# Ц стала заглавной.
Out[98]:
'Цифровая обработка изображений'
In [99]:
# Случай, когда начало строки является пробелом.
' курс по выбору'.capitalize() # Пробел нельзя сделать заглавным.
Out[99]:
' курс по выбору'
In [100]:
# Делает заглавие согласно правилам английского языка.
'python course'.title()
Out[100]:
'Python Course'
In [101]:
# Для русского текста тоже дает корретный результат.
'цифровая обработка изображений'.title()
Out[101]:
'Цифровая Обработка Изображений'

Нормализация строк

In [102]:
'ΣίσυφοςQ'.upper().lower()
Out[102]:
'σίσυφοσq'
In [103]:
'Σίσυφος'.upper().lower() # Последняя буква не та.
Out[103]:
'σίσυφος'
In [104]:
# Приведение к нормальному виду. Важно для машинного обучения.
'ΣίσυφοςQ'.upper().casefold()
Out[104]:
'σίσυφοσq'
In [105]:
# Теперь все буквы совпадают с первой строкой (кроме q).
'Σίσυφος'.upper().casefold()
Out[105]:
'σίσυφοσ'
In [106]:
"ß".lower(), "ß".upper().lower() # Не совпадают.
Out[106]:
('ß', 'ss')
In [107]:
"ß".lower().casefold(), "ß".upper().casefold() # Совпадают.
Out[107]:
('ss', 'ss')

Сложные преобразования

In [108]:
ss = '*\tАня\n*\tКатя'
print(ss)
*	Аня
*	Катя
In [109]:
ss
Out[109]:
'*\tАня\n*\tКатя'
In [110]:
len(ss) 
Out[110]:
12
In [111]:
tt = ss.expandtabs(4) # Заменяем каждый символ табуляции на определенное количество пробелов.
tt
Out[111]:
'*   Аня\n*   Катя'
In [112]:
len(tt) # Каждая табуляция 4 символа.
Out[112]:
16
In [113]:
print(tt)
*   Аня
*   Катя
In [114]:
grades = 'Имя\tБаллы\nАня\t25\nКатя\t27'
In [115]:
print( grades )
Имя	Баллы
Аня	25
Катя	27
In [116]:
print(grades.expandtabs(16))
Имя             Баллы
Аня             25
Катя            27

Замена

In [117]:
'студентка пришла на спецкурс.'.replace('студентка', 'Маша')
Out[117]:
'Маша пришла на спецкурс.'
In [118]:
'студентка пришла на спецкурс.'.replace(['студентка'], ['Маша'])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-118-a33aae781b04> in <module>
----> 1 'студентка пришла на спецкурс.'.replace(['студентка'], ['Маша'])

TypeError: replace() argument 1 must be str, not list

Кодировки

In [119]:
q = 'aa'.encode('utf16') # На выходе тип -- строка байтов.
q, type(q)
Out[119]:
(b'\xff\xfea\x00a\x00', bytes)
In [120]:
win1251 = 'винда'.encode('windows-1251')
win1251
Out[120]:
b'\xe2\xe8\xed\xe4\xe0'
In [121]:
win1251.decode('windows-1251')
Out[121]:
'винда'
In [122]:
win1251.decode('koi8-r') # Старые добрые времена...
Out[122]:
'БХМДЮ'
In [ ]: