Differences between revisions 4 and 5
Revision 4 as of 2018-10-31 06:28:37
Size: 15549
Comment:
Revision 5 as of 2018-10-31 09:42:17
Size: 23460
Comment:
Deletions are marked like this. Additions are marked like this.
Line 257: Line 257:
>>> "Avalidtitle".istitle() # istitle - очень странный метод, проверяющий, состоит ли строка только из букв и является ли первая из них прописной, а остальные - строчными
True
>>> "A non-valid title".istitle()
>>> "Avalidtitle".istitle() # istitle - проверяет, состоит ли строка только из слов, разделённых пробелами, состоящих только из букв и начинающихся с прописной буквы каждое
True
>>> "A nonvalid title".istitle()
Line 269: Line 269:
>>> "A Valid Title".istitle()
True
Line 275: Line 277:
{{{#!highlight pycon
>>> s = "qWe"
>>> s.lower() # lower - преобразование всех букв в строчные
'qwe'
>>> s.upper() # upper - преобразование всех букв в прописные
'QWE'
>>> a.capitalize() # capitalize - преобразование первой буквы в прописную
'Asd asdfsdv zxcdfg%^ 567567 gfhfg oikpi'
>>> a.title() # title - преобразование первых букв всех слов в прописные
'Asd Asdfsdv Zxcdfg%^ 567567 Gfhfg Oikpi'
>>> s.swapcase() # swapcase - сменить регистр всех букв в строке
'QwE'
>>> a.casefold() # casefold - привести строку к такому виду, в котором её возможно сравнивать (>, <) с другими строками вне зависимости от регистра букв
'asd asdfsdv zxcdfg%^ 567567 gfhfg oikpi'
}}}

=== replace ===

Гораздо более интересный метод - '''`replace`'''. Он позволяет заменить вхождения подстроки на заданную строку:

{{{#!highlight pycon
>>> a
'asd aSDFSDv zxcdfg%^ 567567 GFHFG oikpi'
>>> a.replace("SD","----") # По умолчанию заменяются все вхождения
'asd a----F----v zxcdfg%^ 567567 GFHFG oikpi'
>>> a.replace("SD","----",1) # Но можно и ограничить количество замен
'asd a----FSDv zxcdfg%^ 567567 GFHFG oikpi'
}}}

=== Работа с пробельными символами ===

Как убрать лишние пробелы? '''Методами `lstrip`, `rstrip` и `strip`''':

{{{#!highlight pycon
>>> b = " \t za warudo \t "
>>> b.lstrip()
'za warudo \t '
>>> b.rstrip()
' \t za warudo'
>>> b.strip()
'za warudo'
}}}

Кроме того, есть метод '''`expandtabs`''', являющийся наследием второго питона и позволяющий раскрыть символы табуляции в строке по определённым правилам.

=== zfill ===

Метод '''`zfill`''' позволяет дополнить строку, состоящую из цифр, нулями слева, чтобы получить строку длины не меньше указанной:

{{{#!highlight pycon
>>> s = "1"
>>> s.zfill(10)
'0000000001'
>>> s = "-1"
>>> s.zfill(10) # Вот и отличие от ljust: zfill интерпретирует строку именно как число (но это работает только с целыми десятичными числами)
'-000000001'
}}}

== split и join ==

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

=== split ===

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

{{{#!highlight pycon
>>> a
'asd aSDFSDv zxcdfg%^ 567567 GFHFG oikpi'
>>> a.split() # Разбить строку на подстроки по пробельным символам (последовательность пробельных символов как бы считается за один символ)
['asd', 'aSDFSDv', 'zxcdfg%^', '567567', 'GFHFG', 'oikpi']
>>> nn = "123 32 2134 346 657 56 1234 436" # Это очень удобно для анализа ввода с клавиатуры
>>> [int(n) for n in nn.split()]
[123, 32, 2134, 346, 657, 56, 1234, 436]
>>> nn.split("3") # Можно и указать подстроку, по которой выполнять разбиение
['12', ' ', '2 21', '4 ', '46 657 56 12', '4 4', '6']
>>> a = "a,,d,r,,,e,,r" # Если вы указываете подстроку, по которой разбивать данную, вы можете получить в массиве и пустые строки
>>> a.split(",")
['a', '', 'd', 'r', '', '', 'e', '', 'r']
>>> a.split(",,") # Эта подстрока, конечно, не обязана состоять из одного символа
['a', 'd,r', ',e', 'r']
}}}

'''Метод `split` очень, ОЧЕНЬ часто используется при анализе входных данных с клавиатуры.'''

Частный случай работы метода `split`, с некоторыми нюансами (например, независимость от используемого в ос символа новой строки), представляет метод '''`splitlines`''':

{{{#!highlight pycon
>>> s = "This is a long\n text with\n multiple\n line endings\n"
>>> s.splitlines() # splitlines позволяет разбить строку по символам переноса строки (какой бы символ для этого ни использовался в ос)
['This is a long', ' text with', ' multiple', ' line endings']
}}}

=== join ===

Можно выполнить и обратную операцию - объединить несколько строк в одну:

{{{#!highlight pycon
>>> sn = nn.split()
>>> "__".join(sn) # Таким образом можно задать тот разделитель, которым нужно соединять строки
'123__32__2134__346__657__56__1234__436'
>>> "".join(sn) # Т.к. join - метод строки, то, даже если нам не нужен разделитель, хотя бы пустую строку указать придётся
'123322134346657561234436'
}}}

'''Может возникнуть вопрос: зачем это делать с помощью отдельного метода, если есть операция конкатенации `+`?'''

  '''Эффективность. Если только вы хотите объединить не две строки, а больше, попытка сделать это через конкатенацию приведёт к тому, что на каждую конкатенацию двух строк интерпретатор создаст отдельный объект (даже если записать всё выражение в виде "a + b + c + d + ...").'''

  В CPython эту проблему обходят с помощью хака, но вообще полагаться на эффективную реализацию конкатенации строк не стоит (но и ради сложения двух строк использовать `join` смысла нет).

{{{#!wiki red/solid
 /!\ В интернетах если не продолжаются до сих пор, то, по крайней мере, легко находятся старые холивары на тему того, какой метод эффективнее, и не всегда [[https://stackoverflow.com/questions/12169839/which-is-the-preferred-way-to-concatenate-a-string-in-python | наиболее оцененный комментарий]] - верный. Так что будьте аккуратны, сверяйтесь с несколькими источниками и не забывайте проверять даты публикаций.
}}}

== Форматирование строк ==


1. Лекция 6

26 октября 2018 г.

Заметили ошибку или есть предложение? Напишите на почту: romansdidnotcrucify@gmail.com

/!\ ACHTUNG! WORK IN PROGRESS! /!\

Данная страница ещё не закончена и находится в процессе дополнения и переработки. Почитать уже можно, но не забудьте потом заглянуть, когда будет полная версия.

2. Строки

2.1. Задание строк

Строки в питоне - это такие последовательности (смысл их интуитивно понятен - набор символов).

Задавать строки можно четырьмя способами:

  1. с помощью двойных кавычек: "John";

  2. с помощью одинарных кавычек: 'Doe' (никаких отличий от двойных кавычек);

  3. с помощью тройных кавычек: '''John Doe can be multiline''' - позволяют задать многострочную строку (многострочный строковый литерал), а также использовать в её тексте кавычки, не прибегая к специальным символам в исходном коде;

  4. с помощью преобразования объектов других типов: str(12).

Если вы задаёте строку с помощью двойных кавычек - можете спокойно использовать в её тексте одинарные, и наоборот. Если же вы хотите использовать в тексте строки тот же тип кавычек, которым вы обрамляете строку, вам придётся пользоваться одним из инструментов, описанных ниже.

Кстати, обратите внимание на разницу в выводе (функция print, на самом деле, выводит результат метода __str__, a интерпретатор в выводе использует __repr__):

   1 >>> a = '''A multiline string
   2 ... is a string that takes multiple
   3 ... lines of text
   4 ... '''
   5 >>> a    # Интерпретатор при выводе использует результат работы метода объекта __repr__ - он представляет в виде строки внутреннюю структуру объекта 
   6 'A multiline string\nis a string that takes multiple\nlines of text\n'
   7 >>> print(a.__str__())    # __str__ задаёт строковое представление объекта - этот-то метод объекта (если он есть) и использует print
   8 A multiline string
   9 is a string that takes multiple
  10 lines of text
  11 
  12 >>> print(a.__repr__())
  13 'A multiline string\nis a string that takes multiple\nlines of text\n'
  14 

2.2. Спецсимволы (управляющие символы)

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

  1. \n - перенос строки;

  2. \t - табуляция;

  3. \r - символ возврата каретки (подробнее здесь);

  4. \', \" - символ - одинарная/двойная кавычка (вне зависимости от того, с помощью каких кавычек вы задаёте строковый литерал).

   1 >>> print('There will be a\nhuge fall')
   2 There wiil be a
   3 huge fall
   4 >>> print("We need to explore\t\t\touter space")
   5 We need to explore                      outer space
   6 >>> print("I don't want to set the world on fire\rI do!!!")    # Символ возврата каретки переносит наш "курсор" - то место, в которое происходит вывод - в начало строки
   7 I do!!! want to set the world on fire
   8 >>> print("Yep, I'm using \"double quotes\" in a double-quoted string literal")
   9 Yep, I'm using "double quotes" in a double-quoted string literal
  10 

Полную таблицу спецсимволов можно посмотреть здесь

2.3. Коды символов

В разговоре об управляющих символах уместно будет упомянуть функции, позволяющие работать напрямую с кодами символов - ord и chr:

   1 >>> ord("a")    # Получить номер символа в кодировке (ord вернёт десятичное число)
   2 97
   3 >>> ord("abc")    # Обратите внимание, что ord принимает на вход строку именно из одного символа
   4 Traceback (most recent call last):
   5   File "<stdin>", line 1, in <module>
   6 TypeError: ord() expected a character, but string of length 3 found
   7 >>> ord(a)    # И именно строку
   8 Traceback (most recent call last):
   9   File "<stdin>", line 1, in <module>
  10 TypeError: ord() expected a character, but string of length 70 found
  11 >>> ord("ы")    # Символы, не принадлежацие таблице ASCII, кодируются с помощью Юникода
  12 1099
  13 >>> chr(1099)     # chr позволяет по коду символа получить сам символ (символ Юникода тоже)
  14 'ы'
  15 >>> hex(ord("a"))    # Для примера нам потребуются шестнадцатеричные коды символов
  16 '0x61'
  17 >>> hex(ord("ы"))
  18 '0x44b'
  19 >>> print("\x61")    # \xhh - управляющая последовательность, позволяющая вывести ASCII-символ по его коду
  20 a
  21 >>> print("\x04\x4b\x61")    # Для кириллицы не подойдёт
  22 Ka
  23 >>> print("\u044b\x61")    # Символы юникода задаются с помощью управляющих последовательностей \u и \U (за первой следуют 4 шестнадцатеричные цифры, за второй - 8)
  24 ыa
  25 

В питоне, начиная с третьей версии, по умолчанию строки кодируются в UTF-8 (кстати, по ссылке очень хорошо объяснена предыстория вопроса; почитайте, если плохо понимаете, что есть Юникод и с чем его едят).

2.4. Строка как последовательность

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

   1 >>> for i in "QWERTY":
   2 ...     print(i)
   3 ...
   4 Q
   5 W
   6 E
   7 R
   8 T
   9 Y
  10 

Вопрос.

  • Что есть элемент этой последовательности?

В кортежах элементом последовательности является элемент кортежа. В строках же элемент последовательности - строка, состоящая из одного (соответствующего) символа:

   1 >>> a = "Raxacoricofallapatorius"
   2 >>> a[5]    # Строка из одного символа
   3 'o'
   4 >>> a[5:9]    # Новая строка из 4 символов
   5 'oric'
   6 >>> a[8]
   7 'c'
   8 >>> a[8:9]
   9 'c'
  10 >>> a[8] is a[8:9]    # TODO: В чём принципиальное отличие строки от кортежа, кроме того, что каждый элемент строки - тоже строка? Нужно уточнить
  11 True
  12 >>> a[8] is 'c'
  13 True
  14 

К слову, напомню, что строки - неизменяемый тип данных:

   1 >>> a[6] = "v"
   2 Traceback (most recent call last):
   3   File "<stdin>", line 1, in <module>
   4 TypeError: 'str' object does not support item assignment

2.4.1. Операция in

Для строк операция in не осуществляет, как для других последовательностей, поиск первого вхождения элемента (т.е. строки из одного символа). Она осуществляет поиск подстроки в строке:

   1 >>> a
   2 'Raxacoricofallapatorius'
   3 >>> "o" in a    # Это мы уже видели на примере других последовательностей
   4 True
   5 >>> "fall" in a    # А вот это - нечто новое
   6 True
   7 >>> "gravity fall" in a
   8 False
   9 

Поиск подстроки в строке в питоне имеет линейную, а не квадратичную, сложность (спасибо алгоритму Дейкстры).

2.4.2. Операция count

count осуществляет подсчёт количества вхождений подстроки в строку (что тоже является уникальным для строк поведением):

   1 >>> a.count("co")    # Потому что вместо подсчёта вхождений одного элемента последовательности мы считаем количество вхождений целой подпоследовательности
   2 2
   3 

2.5. Методы строк

У строк очень много различных методов, что связано с головными болями, которые разработчики языка имели при работе с ABC/Паскалем:

   1 >>> a = "asd aSDFSDv  zxcdfg%^ 567567 GFHFG oikpi"
   2 >>> dir(a)
   3 ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
   4 

Эти методы делятся на несколько групп.

2.5.1. Поиск

Помимо уже упомянутых in и count, следует знать также об index и find:

   1 >>> a
   2 'asd aSDFSDv  zxcdfg%^ 567567 GFHFG oikpi'
   3 >>> a.index("SDF")    # Найти индекс первого вхождения подстроки в строку
   4 5
   5 >>> a.index("SDF!")    # Если такой подстроки в строке не содержится, выбросить исключение
   6 Traceback (most recent call last):
   7   File "<stdin>", line 1, in <module>
   8 ValueError: substring not found
   9 >>> a.find("SDF")    # find тоже находит первое вхождение подстроки в строку
  10 5
  11 >>> a.find("SDF!")    # Однако в случае неуспеха не выбрасывает ошибку, а возвращает -1
  12 -1
  13 

2.5.2. Проверки

Названия методов из этой группы начинаются на is. Сами эти методы призваны проверять различные свойства строк:

   1 >>> b = "123we"
   2 >>> b.isalnum()    # "is alphanumeric" - содержит ли строка только буквы и цифры
   3 True
   4 >>> b = "123we!"
   5 >>> b.isalnum()
   6 False
   7 >>> b = "123we_"    # К слову, нижнее подчёркивание буквой не считается
   8 >>> b.isalnum()
   9 False
  10 >>> b = "йцукен"    # Буквами считаются и буквы в Юникоде
  11 >>> b.isalnum()
  12 True
  13 >>> "1234".isdigit()    # isdecimal, isdigit, isnumeric - проверка, состоит ли строка из цифр (с некоторыми тонкостями)
  14 True
  15 >>> "1234".isdecimal()
  16 True
  17 >>> "1234F".isdecimal()
  18 False
  19 >>> "1234F".isdigit()
  20 False
  21 >>> b = "123qwe"
  22 >>> b.isidentifier()    # Проверка, может ли строка быть идентификатором (именем объекта), т.е. является ли она последовательностью букв, цифр и _, начинающейся не с цифры
  23 False
  24 >>> b = "_123qwe"
  25 >>> b.isidentifier()
  26 True
  27 >>> "asd".islower()    # islower - состоит ли строка только из строчных букв
  28 True
  29 >>> "aSd".islower()
  30 False
  31 >>> "ASD".isupper()    # isupper - состоит ли строка только из прописных букв
  32 True
  33 >>> "AsD".isupper()
  34 False
  35 >>> "word".isprintable()    # isprintable - состоит ли строка только из печатных символов
  36 True
  37 >>> "word\n".isprintable()
  38 False
  39 >>> "\n\t      \t\n".isspace()    # isspace - состоит ли строка только из пробельных символов
  40 True
  41 >>> "\n\t   !   \t\n".isspace()
  42 False
  43 >>> "Avalidtitle".istitle()    # istitle - проверяет, состоит ли строка только из слов, разделённых пробелами, состоящих только из букв и начинающихся с прописной буквы каждое
  44 True
  45 >>> "A nonvalid title".istitle()
  46 False
  47 >>> "A_non-valid_title".istitle()
  48 False
  49 >>> "Anon-validtitle".istitle()
  50 False
  51 >>> "Anon123alidtitle".istitle()
  52 False
  53 >>> "ANonValidTitle".istitle()
  54 False
  55 >>> "A Valid Title".istitle()
  56 True
  57 

Про разницу между isdecimal, isdigit и isnumeric можно почитать здесь.

2.5.3. Методы форматирования

   1 >>> s = "qWe"
   2 >>> s.lower()    # lower - преобразование всех букв в строчные
   3 'qwe'
   4 >>> s.upper()    # upper - преобразование всех букв в прописные
   5 'QWE'
   6 >>> a.capitalize()    # capitalize - преобразование первой буквы в прописную
   7 'Asd asdfsdv  zxcdfg%^ 567567 gfhfg oikpi'
   8 >>> a.title()    # title - преобразование первых букв всех слов в прописные
   9 'Asd Asdfsdv  Zxcdfg%^ 567567 Gfhfg Oikpi'
  10 >>> s.swapcase()    # swapcase - сменить регистр всех букв в строке
  11 'QwE'
  12 >>> a.casefold()    # casefold - привести строку к такому виду, в котором её возможно сравнивать (>, <) с другими строками вне зависимости от регистра букв
  13 'asd asdfsdv  zxcdfg%^ 567567 gfhfg oikpi'
  14 

2.5.4. replace

Гораздо более интересный метод - replace. Он позволяет заменить вхождения подстроки на заданную строку:

   1 >>> a
   2 'asd aSDFSDv  zxcdfg%^ 567567 GFHFG oikpi'
   3 >>> a.replace("SD","----")    # По умолчанию заменяются все вхождения
   4 'asd a----F----v  zxcdfg%^ 567567 GFHFG oikpi'
   5 >>> a.replace("SD","----",1)    # Но можно и ограничить количество замен
   6 'asd a----FSDv  zxcdfg%^ 567567 GFHFG oikpi'
   7 

2.5.5. Работа с пробельными символами

Как убрать лишние пробелы? Методами lstrip, rstrip и strip:

   1 >>> b = "   \t   za warudo   \t   "
   2 >>> b.lstrip()
   3 'za warudo   \t   '
   4 >>> b.rstrip()
   5 '   \t   za warudo'
   6 >>> b.strip()
   7 'za warudo'
   8 

Кроме того, есть метод expandtabs, являющийся наследием второго питона и позволяющий раскрыть символы табуляции в строке по определённым правилам.

2.5.6. zfill

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

   1 >>> s = "1"
   2 >>> s.zfill(10)
   3 '0000000001'
   4 >>> s = "-1"
   5 >>> s.zfill(10)    # Вот и отличие от ljust: zfill интерпретирует строку именно как число (но это работает только с целыми десятичными числами)
   6 '-000000001'
   7 

2.6. split и join

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

2.6.1. split

Метод split позволяет разбить строку на части по какому-либо символу (по умолчанию - по целым подпоследовательностям, состоящим из пробельных символов). При этом результатом его работы будет список подстрок исходной строки:

   1 >>> a
   2 'asd aSDFSDv  zxcdfg%^ 567567 GFHFG oikpi'
   3 >>> a.split()    # Разбить строку на подстроки по пробельным символам (последовательность пробельных символов как бы считается за один символ)
   4 ['asd', 'aSDFSDv', 'zxcdfg%^', '567567', 'GFHFG', 'oikpi']
   5 >>> nn = "123 32 2134 346 657 56 1234    436"    # Это очень удобно для анализа ввода с клавиатуры
   6 >>> [int(n) for n in nn.split()]
   7 [123, 32, 2134, 346, 657, 56, 1234, 436]
   8 >>> nn.split("3")    # Можно и указать подстроку, по которой выполнять разбиение
   9 ['12', ' ', '2 21', '4 ', '46 657 56 12', '4    4', '6']
  10 >>> a = "a,,d,r,,,e,,r"    # Если вы указываете подстроку, по которой разбивать данную, вы можете получить в массиве и пустые строки
  11 >>> a.split(",")
  12 ['a', '', 'd', 'r', '', '', 'e', '', 'r']
  13 >>> a.split(",,")    # Эта подстрока, конечно, не обязана состоять из одного символа
  14 ['a', 'd,r', ',e', 'r']
  15 

Метод split очень, ОЧЕНЬ часто используется при анализе входных данных с клавиатуры.

Частный случай работы метода split, с некоторыми нюансами (например, независимость от используемого в ос символа новой строки), представляет метод splitlines:

   1 >>> s = "This is a long\n text with\n multiple\n line endings\n"
   2 >>> s.splitlines()    # splitlines позволяет разбить строку по символам переноса строки (какой бы символ для этого ни использовался в ос)
   3 ['This is a long', ' text with', ' multiple', ' line endings']
   4 

2.6.2. join

Можно выполнить и обратную операцию - объединить несколько строк в одну:

   1 >>> sn = nn.split()
   2 >>> "__".join(sn)    # Таким образом можно задать тот разделитель, которым нужно соединять строки
   3 '123__32__2134__346__657__56__1234__436'
   4 >>> "".join(sn)    # Т.к. join - метод строки, то, даже если нам не нужен разделитель, хотя бы пустую строку указать придётся
   5 '123322134346657561234436'
   6 

Может возникнуть вопрос: зачем это делать с помощью отдельного метода, если есть операция конкатенации +?

  • Эффективность. Если только вы хотите объединить не две строки, а больше, попытка сделать это через конкатенацию приведёт к тому, что на каждую конкатенацию двух строк интерпретатор создаст отдельный объект (даже если записать всё выражение в виде "a + b + c + d + ...").

    В CPython эту проблему обходят с помощью хака, но вообще полагаться на эффективную реализацию конкатенации строк не стоит (но и ради сложения двух строк использовать join смысла нет).

  • /!\ В интернетах если не продолжаются до сих пор, то, по крайней мере, легко находятся старые холивары на тему того, какой метод эффективнее, и не всегда наиболее оцененный комментарий - верный. Так что будьте аккуратны, сверяйтесь с несколькими источниками и не забывайте проверять даты публикаций.

2.7. Форматирование строк


LecturesCMC/PythonIntro2018/06_Strings/Conspect (last edited 2018-11-01 03:50:03 by RomanKrivonogov)