Перейти к содержанию

172 уроков, 13 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 2 из 12 Начальный 30 мин 120 XP

Символы и классы символов в регулярках: \d, \w, \s и свои наборы

Цифры, буквы, пробелы и свои наборы в квадратных скобках: полный словарь символьных классов, точка и её аппетиты, экранирование точки в ценах и датах.

Редакция Питоники

Первый шаблон из прошлого урока нашёл дату, но заодно поймал и «12/05/2024» — точка в шаблоне оказалась слишком всеядной. В этом уроке мы соберём полный словарь регулярки: что означает каждый спецсимвол, как описать «только кириллицу» или «всё, кроме цифр» и как найти настоящую точку в цене 3.14. Это самый практичный урок раздела: символьные классы встречаются буквально в каждом шаблоне.

Все примеры ниже исполняются прямо на странице. Меняйте текст и шаблоны в браузерной песочнице — регулярка покажет, что нашлось, а что пропустила.

Что означает \d в регулярке?

\d (от англ. digit — цифра) — одна цифра от 0 до 9. Это короткая замена перечисления [0123456789]: один символ шаблона вместо десяти. У класса есть зеркальный близнец \D (большая буква) — всё, кроме цифры: буквы, пробелы, пунктуация.

Одна деталь, о которой редко предупреждают: в Python 3 класс \d юникодный, то есть цифрой считается не только привычная десятка. Арабско-индийские ٥ и ٦ для \d — такие же цифры, как 5 и 6. Если вам нужны строго ASCII-цифры — например, при валидации номеров документов — пишите набор [0-9] явно.

\d и не-ASCII цифры
import re

print(re.search(r"\d+", "5 и 6").group())        # обычная пятерка
print(re.search(r"\d+", "٥ и ٦").group())        # арабско-индийская - тоже \d
Вывод
5
٥
\d - цифра, \D - всё кроме цифры
import re

code = "2025-Б"

print(re.search(r"\d+", code).group())   # цифры подряд
print(re.search(r"\D+", code).group())   # НЕ-цифры подряд
Вывод
2025
-Б

Пара «класс и его отрицание» работает для всех шести спецсимволов. Плюс после класса — квантификатор «один или больше», он подробно разобран в следующем уроке; здесь он просто склеивает подряд идущие символы в один кусок.

Какие спецсимволы есть ещё: \w, \s и их зеркала?

КлассЧто означаетЗеркальный класс
\dцифра от 0 до 9\D — всё, кроме цифры
\wбуква, цифра или подчёркивание\W — всё, кроме них
\sпробельный символ: пробел, табуляция, перевод строки\S — всё непробельное

Буквы w и s расшифровываются как word character и space. Приятный сюрприз для русскоязычных текстов: в Python 3 классы работают с юникодом, поэтому \w ловит и кириллицу — отдельный шаблон для русских букв не нужен. То же касается \s: неразрывный пробел он тоже считает пробельным, что выручает при чистке текстов, скопированных из вёрстки.

\w понимает кириллицу
import re

print(re.search(r"\w+", "Привет, мир").group())   # кириллица - тоже \w
Вывод
Привет
\w и \s в деле
import re

line = "цена_1: 99 руб"

print(re.search(r"\w+", line).group())           # буквы, цифры, подчёркивания
print(repr(re.search(r"\s\d", line).group()))    # пробел, за ним цифра
Вывод
цена_1
' 9'

Подчёркивание в \w — не опечатка: исторически оно считается «словесным» символом, поэтому цена_1 поймана целиком, включая единицу. А пробел перед девяткой хорошо виден в repr — класс \s честно его съел и показал, что граница числа идёт по пробелу.

Что входит в \s и как резать текст по пробелам?

Класс \s объединяет всё «пустое»: обычный пробел, табуляцию, перевод строки и ещё пару экзотических разделителей. Его зеркало \S — любой видимый символ — неожиданно полезно в практической задаче: разрезать строку на слова, как это делает метод split().

\S+ режет строку на куски
import re

text = "раз\tдва три"

print(re.findall(r"\S+", text))   # все куски между пробелами
Вывод
['раз', 'два', 'три']

Шаблон читается «потяни всё непробельное подряд» — и между находками автоматически остаются только разделители. В отличие от split(), такой приём работает и там, где слова окружены не только пробелами: достаточно расширить логику набором, например [а-яё]+ вытащит только кириллические слова из любой каши.

Что ищет точка в регулярном выражении?

Точка — самый всеядный класс: любой символ, кроме перевода строки. Цифра, буква, запятая, скобка — ей всё равно. Это делает её и самой полезной, и самой опасной.

точка берёт почти всё
import re

print(re.search(r"ра.", "раз, два").group())   # точка - почти любой символ
print(re.search(r"а.б", "а\nб"))               # кроме перевода строки
Вывод
раз
None

Первый поиск нашёл «раз»: точка сыграла роль буквы з. Второй вернул None: между «а» и «б» стоит перевод строки, а точка его принципиально не берёт. Это поведение меняется флагом re.DOTALL — о нём рассказано в уроке про флаги.

Как задать свой набор символов в квадратных скобках?

Шести готовых классов не хватает, например, для «только гласных» или «только кириллицы». Для этого наборы пишут вручную в квадратных скобках: [аое] — один символ из перечисленных. Внутри скобок работают диапазоны через дефис: [0-9], [a-z], [а-яё].

В примерах этого раздела впервые мелькает findall — она возвращает список всех совпадений сразу; подробно её разберём в уроке про методы поиска, а здесь она просто экономит место.

свои наборы: перечисление и комбинация
import re

text = "стол, стул, слон, тлен"

print(re.findall(r"[тс]", text))      # буквы т и с по одной
print(re.findall(r"[тс]л", text))     # т или с, сразу за ними л
Вывод
['с', 'т', 'с', 'т', 'с', 'т']
['сл', 'тл']

Первый шаблон вытащил буквы т и с по одной. Второй показал главное свойство наборов: класс в шаблоне — всегда ровно один символ. Комбинация [тс]л — это уже два класса подряд: «т или с», затем обязательно «л». Диапазон [а-яё] стоит писать именно так, с ё: буква ё живёт отдельно от диапазона а-я, и без явного дописывания она выпадет.

диапазоны: цифры и кириллица
import re

print(re.findall(r"[0-9]+", "в 2025 году, кабинет 7"))
print(re.findall(r"[а-яё]+", "чай и кофе"))
Вывод
['2025', '7']
['чай', 'и', 'кофе']

Диапазоны комбинируются в одном наборе: [a-zA-Z] — латиница в обоих регистрах, [а-яА-ЯёЁ] — кириллица в обоих. Порядок внутри набора не важен: [9087] — те же цифры, что и [0-9], просто перечисленные по одной, без диапазона.

  • нужна цифра? — берите \d;
  • нужна буква или цифра (слово)? — берите \w;
  • нужен пробельный разделитель? — берите \s;
  • нужно что-то своё, чего в готовых классах нет? — пишите свой набор в квадратных скобках.

Что означает крышка внутри набора: [^...]?

Крышка ^ первым символом после [ переворачивает набор: [^0-9] — любой символ, кроме цифры. Та же крышка вне набора означает совсем другое — начало строки; об этом в уроке про якоря.

отрицание набора
import re

print(re.findall(r"[^0-9: ]+", "время: 21:45"))
print(re.findall(r"[^\d]+", "abc123def"))
Вывод
['время']
['abc', 'def']

Шаблон [^0-9: ]+ разобрал строку на слова без цифр, двоеточий и пробелов — отрицание работает сразу на весь набор. Квантификатор + («один или больше подряд») здесь показывает наборы в боевой форме: без него находки печатались бы по одному символу.

Когда нужно экранировать спецсимволы?

Правило короткое: символ, у которого есть особая роль, вне набора ищется через обратный слэш. Точка — \., плюс — \+, скобка — \(. Внутри квадратных скобок почти всё это превращается обратно в обычные символы.

экранирование точки: внутри набора и вне
import re

# внутри набора точка - просто точка, экранировать не нужно
print(re.findall(r"[т.]", "тут и там."))

# а вне набора точку экранируют обратным слэшем
print(re.search(r"\d\.\d", "3.14 и 3,14").group())
Вывод
['т', 'т', 'т', '.']
3.1

Внутри набора [т.] точка — просто точка. А вот вне набора \. обязателен: шаблон \d\.\d нашёл именно «3.1» из «3.14» и не позарился на «3,14» — записанное через запятую число под шаблон с настоящей точкой не подходит.

  • . ^ $ * + ? { } [ ] \ | ( ) — метасимволы, вне набора экранируются слэшем;
  • внутри [ ] спецроль сохраняют только крышка в начале, закрывающая скобка первым же символом и дефис между символами;
  • дефис в начале или конце набора — просто минус: [-+] означает «плюс или минус»;
  • чтобы найти сам обратный слэш, удвойте его: \\.

Если сомневаетесь, нужен ли слэш, — поставьте его. Пропущенный слэш перед метасимволом тихо меняет смысл шаблона, а лишний слэш перед обычной буквой лишь выдаст SyntaxWarning — страховка здесь стоит дешевле, чем её отсутствие.

Как набор символов решает задачу про ФИО?

Соберём выученное в мини-задачу: найти ФИО в строке договора. Классы \w тут не подходят — они взяли бы и цифры, а нам нужны именно буквы с заглавной.

ФИО целиком: три набора подряд
import re

# ФИО целиком: три слова с заглавной
pattern = r"[А-ЯЁ][а-яё]+ [А-ЯЁ][а-яё]+ [А-ЯЁ][а-яё]+"

m = re.search(pattern, "заявку подал Иванов Сергей Петрович 12 мая")
print(m.group())
Вывод
Иванов Сергей Петрович

Читаем: заглавная буква (с Ё на всякий случай), затем строчные — плюс повторяет их сколько нужно, пробел, и так три раза. Шаблон наивный: двойные фамилии и дефисы в них он не осилит, но как скелет для своих данных — рабочий. Дорабатывать его вы уже умеете: допишите нужные символы в наборы. И обратите внимание на пробелы между скобками: пробел в шаблоне — тоже символ, самый обычный, и его требуется ровно столько, сколько в тексте.

Как классы выглядят в других языках?

Символьные классы — редкий пример agreements: они одинаковы почти во всех языках и инструментах, от JavaScript до grep. Вот тот же поиск даты в JavaScript:

тот же шаблон в JavaScript
// JavaScript: шаблон даты
const date = /\d{2}.\d{2}.\d{4}/;

const m = "заказ 14.03.2025".match(date);
console.log(m[0]);   // 14.03.2025
Это JavaScript, а не Python — браузерная песочница исполняет только Python. Смысл символов тот же: \d — цифра, точка — любой символ. Отличается запись: у JS шаблон стоит между слэшами, у Python — это строка в re.search. Фигурные скобки {2} и {4} — квантификаторы из следующего урока.

Выучив классы один раз, вы читаете регулярки в любом языке: меняется обёртка, а словарь остаётся. Лишь отдельные диалекты добавляют своё — например, POSIX-классы [:digit:] в grep, которые в Python не работают.

Что дальше

Словарь собран: шесть спецклассов, точка, собственные наборы с диапазонами и отрицанием, экранирование. Следующий слой — квантификаторы: они отвечают на вопрос «сколько раз?» и превращают «одна цифра» в «четыре цифры» без копипасты. А если однажды понадобится вытащить из страницы атрибуты тегов, начните с урока про извлечение данных в BeautifulSoup — и держите в голове, что регулярки там пригодятся для чистки найденных строк.

Точка — самый всеядный класс регулярки: любой символ, кроме перевода строки, поэтому настоящую точку в цене экранируют слэшем.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

import re

print(re.search(r"\w+@\w+\.ru", "пишите: team@site.ru").group())
import re

print(re.findall(r"[0-9]+", "3 apples, 15 oranges"))
import re

print(re.search(r"3\.14", "число 3,14 или 3.14?").group())
Проверь себя
0 / 5

1. Что означает \w в регулярке Python?

2. С чем совпадёт шаблон r"3.14"?

3. Как задать набор «одна из гласных: а, о, е»?

4. Что означает [^0-9]?

5. Как внутри набора записать обычный минус, а не диапазон?

Карточки терминов
Запомнено: 0 / 6
Практика

В строке спрятан артикул: две заглавные кириллические буквы, дефис, две цифры. Соберите шаблон из наборов символов, найдите артикул и выведите строку «Код: ...».

practice.py
Вопросы и ответы по уроку

Что означает \d в регулярке?

Одну цифру от 0 до 9 — сокращение для [0-9]. Заглавная версия \D означает любой символ, кроме цифры. В Python 3 шаблон \d заодно ловит цифры других юникод-алфавитов, например арабско-индийские; если нужны строго ASCII-цифры, пишите [0-9].

Почему точка в регулярке находит буквы?

Точка — это класс «любой символ, кроме перевода строки», а не настоящая точка. Шаблон 3.14 совпадёт и с «3,14». Чтобы искать точку как точку, экранируйте её: 3\.14. Внутри квадратных скобок экранирование не нужно: [.] — уже обычная точка.

Как искать кириллицу в регулярных выражениях Python?

Через свои наборы: [а-яё] — строчные, [А-ЯЁ] — заглавные, вместе — [а-яА-ЯёЁ]. Буква ё не входит в диапазон а-я, её дописывают отдельно. Класс \w тоже ловит кириллицу, но вместе с цифрами и подчёркиваниями — он шире.

Какие спецсимволы нужно экранировать в регулярных выражениях?

Метасимволы . ^ $ * + ? { } [ ] \ | ( ) вне набора ищутся через обратный слэш. Внутри квадратных скобок почти все они становятся обычными символами. Обратный слэш сам себя экранирует удвоением: \\.

Понравился урок? Сошлитесь на него

«Точка — самый всеядный класс регулярки: любой символ, кроме перевода строки, поэтому настоящую точку в цене экранируют слэшем.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.