Как найти число в строке Python с regex

Как найти число в строке python

Как найти число в строке python

Строки с числами в Python встречаются чаще, чем кажется: логи веб-серверов, CSV-файлы, ответы API и обычный пользовательский ввод почти всегда смешивают цифры с текстом. Метод split() или перебор символов дают результат только в простых случаях, тогда как регулярные выражения позволяют извлекать числа из фразы вроде “Температура -12.5C, влажность 80%” одной строкой кода.

Модуль re предоставляет функции search, findall и finditer, которые работают с шаблонами вида \d+, -?\d+ или -?\d+(?:\.\d+)?. С их помощью можно различать целые, отрицательные и десятичные значения, не задевая посторонние символы вроде процентов, валютных знаков и единиц измерения.

Грамотно составленный regex решает две практические задачи: отсекает ложные совпадения и упрощает последующее преобразование результата в int или float. Например, шаблон -?\d+(?:\.\d+)? сразу возвращает “-12.5” как одну подстроку, а не набор отдельных цифр, что избавляет от ручной сборки числа из фрагментов.

В статье разобраны приемы подбора выражений для разных форматов данных, способы получения одного или нескольких чисел из строки и типовые ошибки, из-за которых regex начинает захватывать лишние символы или пропускать нужные значения.

Импорт модуля re и подготовка строки для поиска чисел

Импорт модуля re и подготовка строки для поиска чисел

Работа с регулярными выражениями в Python начинается с подключения стандартного модуля re через import re. Этот модуль входит в стандартную библиотеку и не требует установки, что делает его доступным в любой среде – от локальных скриптов до серверных приложений и Jupyter-ноутбуков.

Строку, в которой планируется искать числа, важно привести к предсказуемому виду. Если данные поступают из файла или сети, сначала применяют методы strip() и replace(), чтобы убрать переводы строк, неразрывные пробелы и символы табуляции, которые могут разрывать числовые последовательности и мешать совпадению по шаблону.

При работе с текстом в кодировке UTF-8 модуль re корректно обрабатывает кириллицу и латиницу, но числа должны оставаться в стандартном ASCII-формате. Если в исходной строке встречаются экзотические цифры или локализованные разделители, их нужно заранее заменить, например запятые в десятичных дробях на точки с помощью text = text.replace(‘,’, ‘.’).

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

Шаблон регулярного выражения для поиска целых чисел в тексте

Шаблон регулярного выражения для поиска целых чисел в тексте

Базовый шаблон для поиска целых чисел в Python выглядит как \d+, где \d соответствует любой цифре от 0 до 9, а символ + требует наличия одной или более таких цифр подряд. Он находит значения вроде 7, 42 и 2025, но пропускает одиночные цифры, разделённые пробелами или знаками пунктуации.

Чтобы захватывать отрицательные числа, перед группой цифр добавляют необязательный минус: -?\d+. В этом случае выражение распознаёт как -15, так и 15, не включая в совпадение лишние символы.

При разборе строк с буквами и числами важно ограничить границы совпадения, иначе \d+ может вытащить часть идентификатора или кода. Для этого применяют границы слова \b:

  • \b\d+\b – извлекает 123 из “id 123 value”, но не трогает abc123xyz
  • \b-?\d+\b – делает то же самое с учётом отрицательных значений

Если в тексте встречаются числа рядом с единицами измерения или валютой, границы слова могут не сработать. В таких случаях используют явные отрицательные проверки:

  • (? – находит группу цифр, не окружённую другими цифрами
  • (? – аналогичный вариант с поддержкой минуса

Для контроля над допустимым диапазоном можно задать количество цифр через фигурные скобки:

  1. \b\d{1,3}\b – числа от 0 до 999
  2. \b\d{4}\b – ровно четыре цифры, например год

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

Поиск первого числа в строке с помощью re.search

Функция re.search сканирует строку слева направо и возвращает объект совпадения для первого фрагмента, который подходит под заданный шаблон. Для поиска целого числа обычно используют выражение -?\d+, передавая его вторым аргументом вместе с анализируемым текстом.

Если совпадение найдено, метод group() извлекает строковое представление числа, а start() и end() показывают его точные позиции. Это позволяет не только получить значение, но и узнать, где оно расположено, например для последующего вырезания подстроки или проверки контекста вокруг цифр.

При отсутствии чисел re.search возвращает None, поэтому результат нужно проверять перед обращением к его методам. Игнорирование этой проверки приводит к ошибке AttributeError, которая часто возникает при обработке пользовательского ввода или неструктурированных логов.

Для строк с переносами и табуляцией полезно передавать флаг re.DOTALL или предварительно нормализовать текст, чтобы поиск не прерывался на границах строк. В случае регистронезависимых шаблонов чисел флаги не требуются, так как цифры не зависят от алфавита.

Полученную подстроку с числом обычно сразу приводят к int или float, если шаблон допускает знак или десятичную точку, что упрощает дальнейшие расчёты и сравнения.

Извлечение всех чисел из строки через re.findall

Функция re.findall возвращает список всех подстрок, совпавших с шаблоном, что делает её удобной для сбора числовых данных из одного фрагмента текста. При использовании выражения -?\d+ она находит каждое целое число в строке независимо от его позиции и окружения.

Если в шаблоне присутствуют захватывающие группы, findall отдаёт не полные совпадения, а только содержимое этих групп, поэтому для чисел чаще применяют либо незахватывающие группы (?:…), либо выражения без скобок. Это избавляет от неожиданного получения кортежей вместо строк.

Полученный список удобно сразу преобразовать в числовые типы, например через генератор int(x) for x in results, чтобы избежать ошибок при сортировке или суммировании значений.

Шаблон Что извлекается Пример результата
\d+ положительные целые [«12», «300», «7»]
-?\d+ целые со знаком [«-5», «42», «0»]
\b\d{4}\b четырёхзначные числа [«2024», «1999»]

Для длинных строк с большим количеством совпадений стоит учитывать объём возвращаемого списка, так как findall загружает все найденные элементы в память, в отличие от потокового finditer.

Поиск десятичных и отрицательных чисел с учетом знака и точки

Для извлечения дробных значений вместе со знаком применяют шаблон -?\d+(?:\.\d+)?, где -? допускает минус, \d+ отвечает за целую часть, а незахватывающая группа (?:\.\d+)? добавляет необязательную десятичную дробь. Такое выражение корректно находит -12.5, 0.75 и 10 в одном и том же тексте.

Если в данных используются запятые как разделители дробной части, строку предварительно нормализуют заменой , на ., иначе regex воспримет 3,14 как два разных числа. После этого тот же шаблон извлекает значение целиком.

Для защиты от ложных совпадений внутри кодов и идентификаторов выражение дополняют проверками границ: (?. Оно гарантирует, что найденная последовательность не примыкает к другим цифрам и не является фрагментом большего числа.

При последующем преобразовании результата в float стоит учитывать, что строка без точки, например “5”, также будет распознана шаблоном и корректно сконвертируется в 5.0, что упрощает обработку смешанных наборов данных.

Обработка случаев, когда в строке нет чисел

Обработка случаев, когда в строке нет чисел

При работе с re.search отсутствие совпадений означает возврат значения None, поэтому проверка результата должна быть обязательной перед вызовом group(). Это особенно критично при разборе пользовательского ввода и логов, где строки без цифр встречаются регулярно.

Для re.findall ситуация выглядит иначе: функция возвращает пустой список, который удобно проверять по длине или в логическом контексте. Такой подход позволяет сразу отделить строки без числовых данных от тех, где есть хотя бы одно совпадение.

  • проверка if match is None для результата re.search
  • проверка if not results для списка из re.findall
  • возврат значения по умолчанию, например 0 или None, если чисел нет

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

  1. выполнить поиск регулярным выражением
  2. проверить результат на пустоту или None
  3. обработать строку только при наличии совпадений

Такой порядок действий снижает количество исключений и упрощает логику при агрегации числовых данных из больших объёмов текста.

Преобразование найденных строковых чисел в тип int и float

Преобразование найденных строковых чисел в тип int и float

Результаты, полученные через re.search или re.findall, всегда имеют строковый тип, поэтому для вычислений их приводят к числовым форматам стандартными функциями int() и float(). Если шаблон извлекает только целые значения, безопасно использовать int(value), но при наличии десятичной точки требуется float(value).

При работе с универсальным шаблоном вроде -?\d+(?:\.\d+)? удобнее сначала проверять наличие символа . в подстроке и выбирать тип преобразования на его основе. Это избавляет от потери дробной части и позволяет корректно обрабатывать смешанные наборы чисел.

Преобразование следует выполнять внутри блока обработки исключений, так как строки, прошедшие regex, всё равно могут содержать нестандартные форматы, например ведущие плюсы или слишком большие значения, выходящие за диапазон int.

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

Вопрос-ответ:

Почему re.findall иногда возвращает пустой список, хотя в строке есть цифры?

Чаще всего причина в шаблоне. Например, выражение с границами слова \b\d+\b не сработает, если число прилегает к буквам или символам валюты. В строке “USD100” цифры есть, но они не окружены границами слова, поэтому совпадений не будет. В таких случаях лучше использовать \d+ или вариант с отрицательными проверками (?<!\d)\d+(?!\d).

Как получить число из строки, если оно записано с минусом и дробной частью?

Подходит шаблон -?\d+(?:\.\d+)?. Он захватывает и знак, и точку с дробью. После поиска результат приводят к float, например float(match.group()). Это позволяет корректно обработать строки вроде “-12.75 кг” без ручного разрезания текста.

Что лучше использовать для большого текста: re.search или re.findall?

Если нужен только первый числовой фрагмент, re.search прекращает сканирование после нахождения совпадения и создаёт один объект. re.findall проходит всю строку и формирует список всех совпадений, что при длинных логах или файлах может занять больше памяти и времени.

Как не получить ошибку при преобразовании результата regex в число?

Перед вызовом int() или float() нужно убедиться, что поиск дал результат. Для re.search проверяют, что объект не равен None, а для re.findall — что список не пуст. Это исключает попытку конвертации отсутствующих данных и предотвращает TypeError и ValueError.

Ссылка на основную публикацию