Символы и классы символов в регулярках: \d, \w, \s и свои наборы
Цифры, буквы, пробелы и свои наборы в квадратных скобках: полный словарь символьных классов, точка и её аппетиты, экранирование точки в ценах и датах.
Редакция Питоники
Первый шаблон из прошлого урока нашёл дату, но заодно поймал и «12/05/2024» — точка в шаблоне оказалась слишком всеядной. В этом уроке мы соберём полный словарь регулярки: что означает каждый спецсимвол, как описать «только кириллицу» или «всё, кроме цифр» и как найти настоящую точку в цене 3.14. Это самый практичный урок раздела: символьные классы встречаются буквально в каждом шаблоне.
Все примеры ниже исполняются прямо на странице. Меняйте текст и шаблоны в браузерной песочнице — регулярка покажет, что нашлось, а что пропустила.
Что означает \d в регулярке?
\d (от англ. digit — цифра) — одна цифра от 0 до 9. Это короткая замена перечисления [0123456789]: один символ шаблона вместо десяти. У класса есть зеркальный близнец \D (большая буква) — всё, кроме цифры: буквы, пробелы, пунктуация.
Одна деталь, о которой редко предупреждают: в Python 3 класс \d юникодный, то есть цифрой считается не только привычная десятка. Арабско-индийские ٥ и ٦ для \d — такие же цифры, как 5 и 6. Если вам нужны строго ASCII-цифры — например, при валидации номеров документов — пишите набор [0-9] явно.
import re
print(re.search(r"\d+", "5 и 6").group()) # обычная пятерка
print(re.search(r"\d+", "٥ и ٦").group()) # арабско-индийская - тоже \d
5 ٥
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: неразрывный пробел он тоже считает пробельным, что выручает при чистке текстов, скопированных из вёрстки.
import re
print(re.search(r"\w+", "Привет, мир").group()) # кириллица - тоже \w
Привет
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().
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: шаблон даты
const date = /\d{2}.\d{2}.\d{4}/;
const m = "заказ 14.03.2025".match(date);
console.log(m[0]); // 14.03.2025
Выучив классы один раз, вы читаете регулярки в любом языке: меняется обёртка, а словарь остаётся. Лишь отдельные диалекты добавляют своё — например, 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())
1. Что означает \w в регулярке Python?
2. С чем совпадёт шаблон r"3.14"?
3. Как задать набор «одна из гласных: а, о, е»?
4. Что означает [^0-9]?
5. Как внутри набора записать обычный минус, а не диапазон?
В строке спрятан артикул: две заглавные кириллические буквы, дефис, две цифры. Соберите шаблон из наборов символов, найдите артикул и выведите строку «Код: ...».
Что означает \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-канал или свой блог — так о проекте узнают новые читатели.
Что читать дальше
re · Урок 1
Регулярные выражения Python с нуля: первый шаблон и модуль re
Первый шаблон, который находит любую дату в тексте, а не одну конкретную: import re, re.search, raw-строки и объект Match — всё, чтобы перестать бояться регулярки.
re · Урок 3
Квантификаторы в регулярных выражениях: *, +, ? и {n,m}
Сколько раз повторить символ: ноль, один, много или ровно четыре? Четыре квантификатора, диапазоны повторений и две ловушки, из-за которых регулярка находит пустоту.
re · Урок 11
Практикум: регулярные выражения для email, телефонов и дат
Собираем шаблоны, которые вы будете писать чаще всего: адреса почты, российские телефоны в трёх форматах и даты — с нормализацией группами и честными оговорками о границах регулярных выражений.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
json · Урок 1
Что такое JSON и зачем он Python: первый json.dumps
Первое превращение словаря в json-строку одной командой: import json, json.dumps и честный взгляд на кракозябры в выводе — всё исполняется прямо на странице.
json.dumps кириллица
json · Урок 12
Собираем URL для API: urllib.parse
Схема, хост, путь, query: urlparse разбирает адрес, urlencode кодирует кириллицу в проценты, parse_qs читает строку запроса обратно — и весь запрос к API собирается без сети.
python urlencode кириллица
re · Урок 8
Якоря и границы слова в регулярках: ^, $, \b
Якоря ^ и $ не ищут символы — они проверяют позицию, а \b находит слово целиком и не трогает подстроки. Три приёма, после которых шаблоны становятся точными.
якоря регулярных выражений^ в регулярных выражениях