📦 Репозиторий занятия 20

Урок 20. Методы строк

Как работать с репозиторием

Каждая карточка говорит, о чём файл, что он выводит и что в нём искать. Код виден прямо здесь: его можно скопировать одной кнопкой, скачать файл или открыть его целиком.

Маршрут изучения

  1. Прочитайте описание: по нему уже понятно, о чём файл и что он выведет.
  2. Предскажите вывод: сравните своё предположение со строкой «Что выводит».
  3. Запустите: скачайте файл или скопируйте код кнопкой и выполните его у себя.
  4. Измените: поменяйте одно условие или значение и объясните новый результат.

Файлы: рекомендуемый порядок

1
MarkdownРазбор концепции91 строк

Предикатные методы строк: is*() и isidentifier()

less_11__string_methods/theory_01__predicates.md

Сводная таблица из четырнадцати предикатных методов строк (isalpha, isdigit, isalnum, isspace, islower, isupper, istitle, startswith, endswith, isdecimal, isnumeric, isascii, isprintable, isidentifier) с примером и антипримером для каждого. Отдельно углублённо разобран isidentifier() — правила допустимого имени переменной в Python (буквы Unicode, цифры не первым символом, подчёркивание) и важная ловушка: isidentifier() не проверяет совпадение с ключевым словом — для этого нужен модуль keyword.

  • Таблица 14 предикатов: isalpha, isdigit, isalnum, isspace, islower, isupper, istitle…
  • startswith()/endswith() как часть той же таблицы предикатов
  • Правила идентификатора: буквы Unicode, цифры не в начале, _
  • "1var".isidentifier() → False, "привет".isidentifier() → True
  • "for".isidentifier() → True — ловушка, не проверяет ключевые слова
  • keyword.iskeyword("for") → True — правильная проверка
Показать начало файла (91 строк всего)
## Методы проверки предиката

В программировании **предикат** — это функция/метод, которая возвращает логическое значение `True`/`False`

| Метод | Описание                                                                                          | Пример (✅ True)                      | Антипример (❌ False)                   |
|-------|---------------------------------------------------------------------------------------------------|--------------------------------------| -------------------------------------- |
| `isalpha()` | Проверяет, состоит ли строка <br> только из букв.                                                 | `"Привет".isalpha() → True`          | `"Hello123".isalpha() → False`         |
| `isdigit()` | Проверяет, состоит ли строка <br> только из цифр.                                                 | `"12345".isdigit() → True`           | `"12.3".isdigit() → False`             |
| `isalnum()` | Проверяет, состоит ли строка <br> только из букв и цифр.                                          | `"Python3".isalnum() → True`         | `"Hello!".isalnum() → False`           |
| `isspace()` | Проверяет, состоит ли строка <br> только из пробельных символов.                                  | `"   ".isspace() → True`             | `" a ".isspace() → False`              |
| `islower()` | Проверяет, все ли буквы <br> строки в нижнем регистре.                                            | `"python".islower() → True`          | `"Python".islower() → False`           |
| `isupper()` | Проверяет, все ли буквы <br> строки в верхнем регистре.                                           | `"HELLO".isupper() → True`           | `"Hello".isupper() → False`            |
| `istitle()` | Проверяет, каждое ли слово <br> начинается с заглавной буквы и продолжается строчными.            | `"Hello World".istitle() → True`     | `"Hello world".istitle() → False`      |
| `startswith()` | Проверяет, начинается ли строка <br> с указанной подстроки.                                       | `"Python".startswith("Py") → True`   | `"Python".startswith("on") → False`    |
| `endswith()` | Проверяет, заканчивается ли строка <br> указанной подстрокой.                                     | `"Python".endswith("on") → True`     | `"Python".endswith("Py") → False`      |
| `isdecimal()` | Проверяет, состоит ли строка <br> только из **десятичных** цифр.                                  | `"123".isdecimal() → True` <br> `"²".isdigit()  → True` | `"²".isdecimal() → False`              |
| `isnumeric()` | Проверяет, состоит ли строка <br> только из числовых символов <br> (в т.ч. дробей, римских цифр). | `"Ⅷ".isnumeric() → True`             | `"12.5".isnumeric() → False`           |
| `isascii()` | Проверяет, состоит ли строка <br> только из ASCII-символов (0–127).                               | `"Hello!".isascii() → True`          | `"Привет".isascii() → False`           |
| `isprintable()` | Проверяет, все ли символы <br> строки — печатаемые.                                               | `"Hello 123".isprintable() → True`   | `"Hello\nWorld".isprintable() → False` |
| `isidentifier()` | Проверяет, является ли строка <br> допустимым идентификатором в Python.                           | `"variable_1".isidentifier() → True` | `"1variable".isidentifier() → False`   |




## `isidentifier()`.

### Что такое идентификатор в Python

**Идентификатор** — это имя, которое можно использовать для:

* переменных,
* функций,
* классов,
* модулей и т.д.

Примеры идентификаторов:

```python
x
my_var
data123
_underscore
```

---

### Идентификатор в Python МОЖЕТ:

- Может содержать **буквы** (латиница, символы Unicode — например, кириллица).
- Может содержать **цифры**, но **не начинаться** с них.
- Может содержать **подчёркивание `_`**.

### Идентификатор в Python НЕ МОЖЕТ:

- Не может содержать **пробелы, спецсимволы** (`-`, `!`, `@`, и т.д.).
- Не может быть **пустой строкой**.
- Не может совпадать с **ключевым словом Python** (например, `for`, `class`, `def`).

---

…
Проверьте себя: Почему "for".isidentifier() возвращает True, хотя for нельзя использовать как имя переменной в коде?
2
MarkdownРазбор концепции47 строк

isdecimal() vs isdigit() vs isnumeric(): три уровня строгости

less_11__string_methods/theory_02__isdecimal__isdigit__isnumeric.md

Разбирает три похожих метода по нарастающей строгости: isdecimal() принимает только обычные десятичные цифры (в т.ч. разных письменностей), isdigit() дополнительно принимает надстрочные/подстрочные формы вроде «²», а isnumeric() — самый широкий, принимает и римские цифры, и дроби. Наглядная сравнительная таблица на четырёх строках («123», «²», «Ⅷ», «VII») показывает, какой метод что засчитывает как число.

  • isdecimal() — строго 0-9 и их аналоги в других письменностях
  • isdigit() — то же плюс надстрочные цифры вроде "²"
  • isnumeric() — плюс римские цифры ("Ⅷ") и дроби ("⅕")
  • Сравнительная таблица для "123", "²", "Ⅷ", "VII"
  • "VII".isnumeric() → False — это буквы, а не спецсимвол числа
  • ord("Ⅷ") → 8551 — римская цифра как отдельный символ Unicode
Показать начало файла (47 строк всего)
# `isdecimal()` VS `isdigit()` VS `isnumeric()`


## 1. Общее

Все три метода:

* относятся к **предикатным методам строк**;
* возвращают `True` / `False`;
* проверяют, можно ли строку трактовать как **число**.

---

## 2. Отличия

| Метод             | Что учитывает                                                                                       | Примеры `True`                                                                                                                         | Примеры `False`                                                           |
| ----------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| **`isdecimal()`** | **Только десятичные цифры** (0–9). Строго.                                                          | `"123".isdecimal() → True`<br>`"٠١٢٣".isdecimal() → True` (арабские цифры)                                                             | `"²".isdecimal() → False`<br>`"Ⅷ".isdecimal() → False`                    |
| **`isdigit()`**   | Десятичные цифры **и символы цифр вне базового набора** (например, верхние/нижние индексы).         | `"123".isdigit() → True`<br>`"²".isdigit() → True`                                                                                     | `"Ⅷ".isdigit() → False`<br>`"VII".isdigit() → False`                      |
| **`isnumeric()`** | Всё, что можно считать числом: десятичные цифры, индексы, дроби, римские цифры и спецсимволы чисел. | `"123".isnumeric() → True`<br>`"²".isnumeric() → True`<br>`"Ⅷ".isnumeric() → True` (римская 8)<br>`"⅕".isnumeric() → True` (дробь 1/5) | `"VII".isnumeric() → False` (потому что это буквы, а не спецсимвол числа) |

---

## 3. Наглядное различие

| Строка   | `.isdecimal()` | `.isdigit()` | `.isnumeric()` | Комментарий                 |
|----------| -------------- | ------------ | -------------- | --------------------------- |
| `"123"`  | ✅ True         | ✅ True       | ✅ True         | Обычные десятичные цифры    |
| `"²"`    | ❌ False        | ✅ True       | ✅ True         | Надстрочная цифра (степень) |
| `"Ⅷ"`    | ❌ False        | ❌ False      | ✅ True         | Римская цифра (8)           |
| `"VII"`  | ❌ False        | ❌ False      | ❌ False        | Буквы, а не число           |


---

## 4. Приоритеты "строгости"

* **`isdecimal()`** → самый строгий → только обычные цифры (в том числе в разных письменностях).
* **`isdigit()`** → шире → цифры + надстрочные/подстрочные формы.
* **`isnumeric()`** → самое общее → всё, что может представлять число (включая римские цифры, дроби).

⚠️ Важно: Римское "восемь" (`"Ⅷ"`) - это символ Unicode!
```python
print("Ⅷ".isnumeric())  # True
print(len("Ⅷ"))         # 1 
print(ord("Ⅷ"))         # 8551
```
Проверьте себя: Почему "Ⅷ" (римская восьмёрка) — это isnumeric()==True, но isdigit()==False, хотя визуально это тоже «число»?
3
MarkdownРазбор концепции32 строк

Поиск подстроки: find/rfind/index/rindex/count

less_11__string_methods/theory_03__looking_for_substr_in_str.md

Сводная таблица методов поиска подстроки с акцентом на главное различие пар find/index и rfind/rindex: find возвращает -1 при неудаче, а index кидает ValueError. Даёт рекомендацию — index обычно используют вместе с проверкой in, чтобы избежать необработанного исключения, и показывает count() для подсчёта числа вхождений.

  • find(sub) / rfind(sub) — возвращают -1 при неудаче
  • index(sub) / rindex(sub) — кидают ValueError при неудаче
  • startswith()/endswith() — тоже в этой таблице, для сравнения
  • count(sub) — считает число вхождений подстроки
  • if 'sub' in text: text.index('sub') — безопасный паттерн использования index
Показать начало файла (32 строк всего)
# Методы поиска подстроки в строке

| Метод                               | Что делает                                     | Возвращает при успехе | При неудаче  | Пример                             |
|-------------------------------------| ---------------------------------------------- | --------------------- | ------------ | ---------------------------------- |
| `find(sub[, start[, end]])`         | Индекс первого вхождения подстроки             | `int` (позиция)       | `-1`         | `"hello world".find("world")  # 6` |
| `rfind(sub[, start[, end]])`        | Индекс последнего вхождения подстроки          | `int` (позиция)       | `-1`         | `"test test".rfind("test")  # 5`   |
| `index(sub[, start[, end]])`        | Как `find`, но с исключением                   | `int` (позиция)       | `ValueError` | `"hello".index("he")  # 0`         |
| `rindex(sub[, start[, end]])`       | Как `rfind`, но с исключением                  | `int` (позиция)       | `ValueError` | `"banana".rindex("na")  # 4`       |
| `startswith(prefix[, start[, end]])` | Проверяет, начинается ли строка с подстроки    | `True` / `False`      | `False`      | `"Python".startswith("Py")  # True` |
| `endswith(suffix[, start[, end]])`  | Проверяет, оканчивается ли строка на подстроку | `True` / `False`      | `False`      | `"Python".endswith("on")  # True`  |
| `count(sub[, start[, end]])`        | Считает количество вхождений подстроки | `int` (число вхождений) | 0 | `"banana".count("na") # 2` |
---

### Итоговое заключение

* Для **поиска позиции подстроки**:

  * `find` и `rfind` безопаснее (возвращают `-1`, если не нашли).
  * `index` и `rindex` строже (вызывают `ValueError`, если не нашли).
  
Поэтому `index` и `rindex` обычно используют вместе с проверкой

```python
text = 'substring substring'
if 'sub' in text:
    print(text.index('sub'))   # 0
    print(text.rindex('sub'))  # 13
else:
    print('Нет совпадений')
```

Проверьте себя: Почему рекомендуется оборачивать index() проверкой in, а не просто ловить ValueError через try/except?
4
MarkdownРазбор концепции30 строк

Методы регистра: upper/lower/capitalize/title/swapcase/casefold

less_11__string_methods/theory_04__changing_case_methods.md

Таблица шести методов изменения регистра с примером на каждый. Главная содержательная часть — сравнение lower() и casefold() на неанглийских буквах: для латиницы они одинаковы, но для немецкой ß и турецкой İ дают разный результат (casefold корректно разворачивает ß в 'ss', lower — нет), что демонстрируется через ord() итоговых символов.

  • upper(), lower(), capitalize(), title(), swapcase() — базовая таблица
  • casefold() — регистронезависимое сравнение с учётом национального алфавита
  • "ß".lower() → "ß" (не меняется) vs "ß".casefold() → "ss"
  • "İ".lower() → "i̇" (два символа) vs "İ".casefold() → "i" (один символ)
Показать начало файла (30 строк всего)
## Методы изменения регистра


| Метод          | Что делает                                                 | Пример                                        |
| -------------- |------------------------------------------------------------| --------------------------------------------- |
| `upper()`      | Преобразует все буквы в верхний регистр                    | `"hello".upper()  # "HELLO"`                  |
| `lower()`      | Преобразует все буквы в нижний регистр                     | `"HELLO".lower()  # "hello"`                  |
| `capitalize()` | Делает первую букву заглавной, остальные — строчными       | `"hello world".capitalize()  # "Hello world"` |
| `title()`      | Делает первую букву каждого слова заглавной                | `"hello world".title()  # "Hello World"`      |
| `swapcase()`   | Меняет регистр каждой буквы на противоположный             | `"Hello World".swapcase()  # "hELLO wORLD"`   |
| `casefold()`   | Приводит строку к регистру с учётом национального алфавита | `"ß".casefold()  # "ss"`                      |

---


### `lower()` VS `casefold()`

На некоторых локальных алфавитах метод `casefold()` ведёт себя более корректно:

| Метод        | Что делает                          | Пример           | Результат                          | `ord()` результата |
| ------------ |-------------------------------------| ---------------- | ---------------------------------- | ------------------ |
| `lower()`    | Преобразует букву в строчную        | `"A".lower()`    | `"a"`                              | `97`               |
| `casefold()` | Для ланиницы работает так же        | `"A".casefold()` | `"a"`                              | `97`               |
| `lower()`    | Применяется к немецкому символу `ß` | `"ß".lower()`    | `"ß"`                              | `223`              |
| `casefold()` | Применяется к немецкому символу `ß` | `"ß".casefold()` | `"ss"`                             | `115, 115`         |
| `lower()`    | Применяется к турецкой букве `İ`    | `"İ".lower()`    | `"i̇"` (i + комбинированная точка) | `105, 775`         |
| `casefold()` | Применяется к турецкой букве `İ`    | `"İ".casefold()` | `"i"`                              | `105`              |


Проверьте себя: Если сравнивать два варианта написания одного слова с ß и с ss, какой метод — lower() или casefold() — надёжнее использовать для сравнения без учёта регистра, и почему?
5
MarkdownРазбор концепции72 строк

str.replace(old, new, count): замена подстроки

less_11__string_methods/theory_05__replace.md

Разбирает сигнатуру replace() с необязательным параметром count (ограничение числа замен слева направо) и показывает пять сценариев: полная замена всех вхождений, замена с ограничением по count, точечное изменение регистра одного символа, замена несуществующей подстроки (строка остаётся как есть) и необычный приём — replace("", "-") вставляет разделитель между каждым символом строки.

  • text.replace("яблоко", "банан") — замена всех вхождений
  • text.replace("красный", "зелёный", 2) — ограничение по count
  • text.replace("l", "L") — точечная замена регистра одного символа
  • text.replace("java", "C++") на строке без java — строка не меняется
  • "abc".replace("", "-") → "-a-b-c-" — вставка разделителя между символами
  • Цепочка .replace(",", "").replace("!", "") — удаление знаков препинания
Показать начало файла (72 строк всего)

## `replace`

```python
str.replace(old, new[, count])
```

| Параметр                 | Описание                                                                |
| ------------------------ | ----------------------------------------------------------------------- |
| `old`                    | Подстрока, которую нужно заменить                                       |
| `new`                    | Подстрока, на которую будет произведена замена                          |
| `count` (необязательный) | Максимальное количество замен. Если не указан, заменяются все вхождения |

Метода меняет указанные части исходной строки (`old`) на предложенные (`new`).  
По умолчанию - меняется всё, но число замен можно ограничить.  
В этом случае, замены считаются слева - направо.

Если совпадений не найдено - исходная строка остаётся без изменений.

---

## Примеры

### 1 Замена всех вхождений

```python
text = "яблоко, апельсин, яблоко"
result = text.replace("яблоко", "банан")
print(result)  
# "банан, апельсин, банан"
```

### 2 Замена с ограничением по количеству

```python
text = "красный, красный, красный"
result = text.replace("красный", "зелёный", 2)
print(result)  
# "зелёный, зелёный, красный"
```

### 3 Изменение регистра символа

```python
text = "hello world"
result = text.replace("l", "L")
print(result)  
# "heLLo worLd"
```

### 4 Замена подстроки, которой нет

```python
text = "python"
result = text.replace("java", "C++")
print(result)  
# "python"  (без изменений)
```

### 5 "Окружаем" разделителем каждый символ строки 
…
Проверьте себя: Почему "abc".replace("", "-") даёт "-a-b-c-" с четырьмя дефисами, а не с тремя (по числу символов)?
6
MarkdownРазбор концепции46 строк

strip/lstrip/rstrip: удаление символов с краёв строки

less_11__string_methods/theory_06__strip_lstrip_rstrip.md

Показывает три метода очистки краёв строки — с обеих сторон, только слева, только справа — сначала на пробелах, потом на произвольных символах через аргумент. Ключевое предупреждение файла: strip(набор_символов) удаляет символы ДО ПЕРВОГО символа не из набора, а не любые вхождения внутри строки, что демонстрируется на примере 'abcdeabc'.strip('ac'), где внутренние a/c не тронуты.

  • text.strip() / lstrip() / rstrip() — удаление пробелов по краям
  • text.strip("/") — удаление конкретного символа с обеих сторон
  • text.strip(".,!") — удаление набора из нескольких символов
  • "abcdeabc".strip("ac") → "bcdeab" — символы внутри строки не трогаются
Показать начало файла (46 строк всего)
## `strip()`, `lstrip()`, `rstrip()`



| Метод      | Что делает                                            | Пример                              |
| ---------- | ----------------------------------------------------- |-------------------------------------|
| `strip()`  | Убирает указанные символы **с начала и конца строки** | `"  hello  ".strip()  # "hello"`    |
| `lstrip()` | Убирает указанные символы **только слева**            | `"  hello  ".lstrip()  # "hello  "` |
| `rstrip()` | Убирает указанные символы **только справа**           | `"  hello  ".rstrip()  # "  hello"` |

---

## Примеры

### 1 Обычное удаление пробелов

```python
text = "   Python   "
print(text.strip())   # "Python"
print(text.lstrip())  # "Python   "
print(text.rstrip())  # "   Python"
```

### 2 Удаление конкретных символов

```python
text = "///hello///"
print(text.strip("/"))   # "hello"
print(text.lstrip("/"))  # "hello///"
print(text.rstrip("/"))  # "///hello"
```

### 3. Удаление нескольких символов

```python
text = ".,!hello!.,"
print(text.strip(".,!"))  # "hello"
```

**ВАЖНО**: Символы удаляются ДО ПЕРВОГО символа НЕ ИЗ указанного набора символов:  


```python
text = "abcdeabc"
print(text.strip("ac"))  # "bcdeab"  (удаляет все `a` и `c` с концов, не внутри)
```
Проверьте себя: Почему "abcdeabc".strip("ac") не удаляет 'a' и 'c', стоящие в середине строки (в 'de**a**bc')?
7
MarkdownРазбор концепции57 строк

split() и join(): разбиение строки на список и сборка обратно

less_11__string_methods/theory_07__split__vs__join.md

Пара взаимно обратных методов: split(sep, maxsplit) режет строку на список по разделителю (с особым поведением при sep=None — несколько пробелов подряд считаются одним разделителем) и join(iterable) склеивает список обратно в строку вокруг заданного объединителя. Метафора файла — split() как ножницы, join() как клей — задаёт интуицию для обоих методов сразу.

  • text.split(",") — разбиение по явному разделителю
  • text2.split() без аргумента — несколько пробелов подряд как один разделитель
  • text3.split(",", 2) — ограничение числа разбиений через maxsplit
  • ", ".join(words) — сборка списка строк в одну строку
  • "".join(list("Python")) — разборка строки на символы и сборка обратно
Показать начало файла (57 строк всего)
# Методы разделения и "сбора" строки

 
## 1 Метод `split()`

Синтаксис: `split(sep=None, maxsplit=-1)`  

Разбивает строку на список подстрок по указанному разделителю `sep`.  
Если `sep` не указан, - "разбивает" по пробельным символам.   
Допустимо ограничить число разбиений, указав `maxsplit`> 0

Если слово разделено несколькими пробелами подряд, они объединяются (см. пример)


### Примеры

```python
text = "apple,banana,cherry"
fruits = text.split(",")
print(fruits)  
# ['apple', 'banana', 'cherry']

text2 = "one      two       three"
words = text2.split()  # несколько пробелов подряд считаются как один!
print(words)  
# ['one', 'two', 'three']

text3 = "a,b,c,d,e"
print(text3.split(",", 2))  
# ['a', 'b', 'c,d,e']  (максимум 2 разбиения)
```

### 2. Метод `join()`

Синтаксис: `join(iterable)`

Объединяет элементы итерируемого объекта в одну строку вокруг "объединителя",  
указанного как аргумент метода `join()`. 

```python
words = ['apple', 'banana', 'cherry']
text = ", ".join(words)
print(text)  
# "apple, banana, cherry"

text = 'Python'
letters = list(text)  # ['P', 'y', 't', 'h', 'o', 'n']
print("".join(letters))  
# 'Python'
```


## Резюме

* `split()` — как ножницы, режет строку по указанному разделителю, превращая её в список строк.
* `join()` — как клей, склеивает список строк в одну строку, вокруг "объединителя".
Проверьте себя: Почему "one two three".split() даёт ['one', 'two', 'three'] без пустых строк, хотя между словами разное число пробелов?