Re.findall: примеры (PYTHON)
re.findall(pattern, string, flags): listОписание функции re.findall
Функция findall из модуля re используется для поиска всех непересекающихся соответствий шаблону регулярного выражения в строке. Она возвращает список строк или кортежей, в зависимости от наличия групп в шаблоне.
Использование функции целесообразно при необходимости извлечения всех фрагментов текста, соответствующих заданному шаблону. Например, это может быть поиск всех email-адресов, хештегов или числовых значений в документе.
Аргументы функции
- pattern (обязательный): строка или скомпилированное регулярное выражение (объект Pattern).
- string (обязательный): строка, в которой осуществляется поиск.
- flags (опциональный): один или несколько флагов, изменяющих поведение регулярного выражения. Например, re.IGNORECASE для регистронезависимого поиска.
Возвращаемое значение
- Если в шаблоне нет групп, возвращается список строк, соответствующих всему шаблону.
- Если в шаблоне есть одна группа, возвращается список строк, соответствующих этой группе.
- Если групп несколько, возвращается список кортежей, каждый из которых содержит строки, соответствующие группам.
- При отсутствии совпадений возвращается пустой список.
Примеры использования re.findall
Простейший пример поиска всех чисел в строке:
import re
text = 'В 2024 году было 12 месяцев и 365 дней.'
result = re.findall(r'\d+', text)
print(result)['2024', '12', '365']
Использование флага для регистронезависимого поиска:
result = re.findall(r'python', 'Python is python', flags=re.IGNORECASE)
print(result)['Python', 'python']
Работа с группами. Поиск пар 'ключ=значение':
text = 'width=200 height=300'
result = re.findall(r'(\w+)=(\d+)', text)
print(result)[('width', '200'), ('height', '300')]Использование скомпилированного регулярного выражения:
pattern = re.compile(r'#[0-9a-fA-F]{6}')
colors = pattern.findall('Цвета: #ff0000, #00ff00, #0000ff')
print(colors)['#ff0000', '#00ff00', '#0000ff']
Похожие функции в Python
Модуль re предлагает несколько функций для поиска по шаблону.
re.finditer
Функция finditer возвращает итератор с объектами Match для каждого совпадения. Ее использование предпочтительнее при обработке больших текстов, так как не загружает все результаты в память сразу. Также она предоставляет полную информацию о позиции каждого совпадения.
re.search
Функция search находит только первое совпадение в строке и возвращает объект Match или None. Используется, когда нужно проверить наличие шаблона и получить детали по первому совпадению.
re.match
Функция match ищет совпадение только в начале строки. Ее применение логично для проверки формата строк, например, при валидации ввода.
re.fullmatch
Функция fullmatch требует, чтобы вся строка целиком соответствовала шаблону. Это удобно для строгой проверки данных на соответствие шаблону.
Выбор функции зависит от задачи: findall - для извлечения всех фрагментов, finditer - для пошаговой обработки, search/match - для проверки наличия.
Типичные ошибки
Неверная интерпретация возвращаемого значения при наличии групп
Наличие групп в шаблоне меняет формат результата, что иногда приводит к неожиданностям.
import re
# Ожидание списка полных совпадений, но в шаблоне есть группа.
result = re.findall(r'(\d+)', 'abc123def')
print(result)['123']
Здесь возвращается список строк, соответствующих группе, а не всему шаблону.
Использование жадных квантификаторов, приводящее к пропуску совпадений
Жадные квантификаторы захватывают максимально возможное количество символов, что может объединять несколько нужных фрагментов в один.
text = '"one" "two" "three"'
result = re.findall(r'".*"', text)
print(result)['"one" "two" "three"']
Для поиска отдельных цитат следует использовать нежадный квантификатор .*?.
Ошибки из-за специальных символов в строке шаблона
Символы, такие как обратная косая черта, требуют экранирования как в строковом литерале Python, так и в синтаксисе регулярных выражений.
# Ошибка: попытка найти обратную косую черту.
# Неправильно:
try:
re.findall('\', 'text')
except re.error as e:
print(e)bad escape \ at position 0
Правильно использовать сырые строки: r'\\'.
Смешение строк и байтов
Попытка использовать байтовые строки с шаблоном в виде обычной строки вызывает ошибку.
# Неправильно:
try:
re.findall(r'\d+', b'123')
except TypeError as e:
print(e)cannot use a string pattern on a bytes-like object
Для байтовых строк шаблон также должен быть байтовым: re.findall(b'\\d+', b'123').
Изменения в последних версиях Python
В Python 3.7 была добавлена поддержка флага re.ASCII по умолчанию для строковых шаблонов, скомпилированных с флагом re.A. Это делает поведение регулярных выражений более последовательным.
В Python 3.11 функция re.findall стала работать быстрее для некоторых типов шаблонов благодаря внутренним оптимизациям механизма регулярных выражений.
Начиная с Python 3.6, шаблоны в формате строк с вставленными нулевыми байтами больше не допускаются и вызывают предупреждение DeprecationWarning, а в Python 3.11 - ошибку.
В Python 3.14 планируются дальнейшие улучшения производительности.
Расширенные примеры
Извлечение данных из структурированного текста, например, лог-файла.
log = """
[ERROR] 2023-10-05 10:15:23 Connection failed
[INFO] 2023-10-05 10:15:25 Retrying...
[ERROR] 2023-10-05 10:15:30 Timeout
"""
# Извлечение уровней логов и сообщений
entries = re.findall(r'\[(\w+)\] (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (.+)', log)
for level, timestamp, message in entries:
print(f'{level} at {timestamp}: {message}')ERROR at 2023-10-05 10:15:23: Connection failed INFO at 2023-10-05 10:15:25: Retrying... ERROR at 2023-10-05 10:15:30: Timeout
Поиск всех слов, начинающихся с заглавной буквы (поиск имен собственных).
text = 'В Москве и Париже живут люди.'
result = re.findall(r'\b[А-ЯЁA-Z][а-яёa-z]*\b', text)
print(result)['Москве', 'Париже']
Использование просмотра вперед и назад для поиска с контекстом.
# Найти числа, после которых стоит 'px'
text = 'width: 200px, height: 300px, depth: 400cm'
result = re.findall(r'\d+(?=px)', text)
print(result)['200', '300']
Обработка многострочного текста с флагом re.MULTILINE.
text = """
Name: John
Age: 30
City: NY
Name: Anna
Age: 25
"""
# Извлечь все значения после 'Age:'
ages = re.findall(r'^Age: (\d+)$', text, flags=re.MULTILINE)
print(ages)['30', '25']
Работа с повторяющимися группами. Поиск всех пар тегов в HTML-подобной строке.
html = 'testsampleanother'
tags = re.findall(r'<([a-z]+)>(.*?)\1>', html)
print(tags)[('div', 'test'), ('span', 'sample'), ('div', 'another')]Извлечение данных с перекрывающимися совпадениями с использованием позитивного просмотра вперед.
# Найти все перекрывающиеся подстроки 'aba' в строке 'ababa'
text = 'ababa'
result = re.findall(r'(?=(aba))', text)
print(result)['aba', 'aba']
Аналоги функции в других языках
JavaScript
Метод String.prototype.match с глобальным флагом g возвращает массив всех совпадений. Если в регулярном выражении есть группы, они тоже включаются в результат.
let text = 'a1 b2 c3';
let result = text.match(/\w\d/g);
console.log(result);['a1', 'b2', 'c3']
PHP
Функция preg_match_all выполняет глобальный поиск по шаблону. Результат помещается в массив, структура которого зависит от флагов.
$text = 'a1 b2 c3';
preg_match_all('/\w\d/', $text, $matches);
print_r($matches[0]);Array
(
[0] => a1
[1] => b2
[2] => c3
)Java
Класс Matcher используется для поиска. Для получения всех результатов применяется цикл с методом find.
import java.util.regex.*;
Pattern p = Pattern.compile("\\w\\d");
Matcher m = p.matcher("a1 b2 c3");
while (m.find()) {
System.out.println(m.group());
}a1 b2 c3
C#
Метод Regex.Matches возвращает коллекцию объектов Match.
using System.Text.RegularExpressions;
var matches = Regex.Matches("a1 b2 c3", @"\w\d");
foreach (Match m in matches) Console.WriteLine(m.Value);a1 b2 c3
Golang
Метод FindAllString у типа Regexp возвращает срез строк. В отличие от Python, группы не выделяются отдельно в этом методе.
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`\w\d`)
result := re.FindAllString("a1 b2 c3", -1)
fmt.Println(result)
}[a1 b2 c3]
Kotlin
Метод findAll у объекта Regex возвращает последовательность результатов.
val text = "a1 b2 c3"
val result = Regex("\\w\\d").findAll(text).map { it.value }.toList()
println(result)[a1, b2, c3]
Lua
Функция string.gmatch возвращает итератор для всех совпадений.
for match in string.gmatch("a1 b2 c3", "%w%d") do
print(match)
enda1 b2 c3
SQL (PostgreSQL)
Функция regexp_matches возвращает множество строк с массивами совпадений. Работает в контексте запроса.
SELECT regexp_matches('a1 b2 c3', '\w\d', 'g');{a1}
{b2}
{c3}Основные отличия от Python: способ возврата данных (массивы, итераторы, коллекции), синтаксис регулярных выражений и обработка групп.