Извлечение цифр из строки в PHP: лучшие практики
Как оставить только цифры в строке: основные методы и их особенности
При обработке строк в PHP часто возникает необходимость извлечь только цифровые символы, отбросив всё остальное. Это может потребоваться при очистке телефонных номеров, идентификаторов, ввода форм или парсинге данных. Рассмотрим несколько решений - от самого эффективного до альтернативных подходов, с примерами и анализом возможных проблем.
Как быстро удалить все нецифровые символы из строки с помощью регулярного выражения?
Наиболее производительный и короткий способ - функция preg_replace. Она заменяет все символы, не являющиеся десятичными цифрами (0–9), на пустую строку. Для этого используется класс символов \D (все, кроме цифр) или инвертированный класс [^0-9].
$original = "Телефон: +7 (123) 456-78-90";
$digits_only = preg_replace('/\D/', '', $original);
echo $digits_only;
71234567890
Это решение подходит для любых строк, включая кириллицу, пробелы, знаки препинания. Цель: получить сплошную последовательность цифр независимо от формата исходных данных.
- Если строка не содержит цифр, результатом будет пустая строка. Это нормально, но иногда может ввести в заблуждение при дальнейшей проверке.
- Регулярное выражение без модификатора u работает только с однобайтовыми кодировками. Если строка в UTF-8 и содержит не-ASCII символы (например, буквы «ё»), проблем не возникает, так как \D удаляет любые нецифровые байты. Однако при работе с многобайтовыми символами, которые могут быть ошибочно восприняты, стоит добавить модификатор u: preg_replace('/\D/u', '', $string).
- Не учитываются цифры, находящиеся в других системах счисления (например, арабо-индийские). Если нужны только арабские цифры (0–9), этот метод корректен.
Как очистить строку через фильтр FILTER_SANITIZE_NUMBER_INT?
PHP предоставляет встроенные фильтры для очистки данных. FILTER_SANITIZE_NUMBER_INT удаляет все символы, кроме цифр, а также знаков плюс (+) и минус (-). Если требуется оставить только цифры, после фильтрации нужно дополнительно убрать знаки.
$dirty = "Цена: -1 234 руб.";
$filtered = filter_var($dirty, FILTER_SANITIZE_NUMBER_INT);
echo $filtered;
-1234
Чтобы оставить только цифры, удаляем знаки:
$digits = str_replace(['+', '-'], '', $filtered);
Цель: быстро извлечь число со знаком, а затем при необходимости отбросить знак.
- Фильтр не удаляет знак минус, если он стоит не на первой позиции (например, в середине строки). В итоге могут появиться лишние дефисы.
- При отсутствии цифр фильтр вернет пустую строку.
Как извлечь цифры, перебирая строку посимвольно?
Классический ручной подход: проход по каждому символу и проверка с помощью ctype_digit.
$str = "Код ошибки: 404";
$result = '';
for ($i = 0; $i < strlen($str); $i++) {
if (ctype_digit($str[$i])) {
$result .= $str[$i];
}
}
echo $result;
404
Цель: когда требуется полный контроль над процессом (например, одновременная запись позиций цифр) или нежелательны регулярные выражения.
- Медленнее регулярных выражений на длинных строках.
- Не работает с многобайтовыми кодировками, так как $str[$i] обращается к байту, а не к символу. Используйте mb_strlen и mb_substr для UTF-8.
Как собрать цифры с помощью preg_match_all и implode?
Если нужно не удалить нецифровые символы, а именно найти все цифры и объединить их, можно использовать preg_match_all с шаблоном \d и соединить результат.
$text = "a1b2c3";
preg_match_all('/\d/', $text, $matches);
$digits = implode('', $matches[0]);
echo $digits;
123
Цель: получить массив найденных цифр для дальнейшей обработки (например, подсчета количества).
Как использовать str_replace для удаления известных нецифровых символов?
Если набор символов, которые нужно удалить, ограничен (например, только пробелы и дефисы), можно применить str_replace.
$phone = "+7-912-345-67-89";
$cleaned = str_replace(['+', '-', ' ', '(', ')'], '', $phone);
echo $cleaned;
79123456789
Цель: быстро очистить строку, когда известен точный перечень «мусорных» символов. Не подходит для неизвестных или переменных форматов.
- Если появятся новые нецифровые символы (например, буквы), они останутся.
- Неэффективно при большом количестве заменяемых символов.
Как извлечь только цифры с помощью intval и floatval?
Эти функции преобразуют строку в число, отбрасывая все нецифровые символы, начиная с первого нецифрового. Однако результат может отличаться от ожидаемого, если цифры идут не с начала.
$str = "abc123def";
echo intval($str); // 0
$str2 = "123abc";
echo intval($str2); // 123
Цель: получить целое или вещественное число из строки, которая начинается с цифр. Не подходит для извлечения всех цифр, расположенных в середине или конце.
<?php
// 1. Удаление всех нецифровых символов с учётом Unicode
$str_unicode = "Ваш заказ № 42 – 1000 руб.";
$digits_unicode = preg_replace('/[^0-9]/u', '', $str_unicode);
echo "Unicode: $digits_unicode\n";
// 2. Извлечение цифр из строки с несколькими числами (с сохранением порядка)
$mixed = "item_12, price_34, qty_56";
$only_digits = preg_replace('/\D/', '', $mixed);
echo "Mixed: $only_digits\n";
// 3. Работа с пустой строкой
$empty_input = "Нет цифр";
$result_empty = preg_replace('/\D/', '', $empty_input);
echo "Empty result: '{$result_empty}' (длина " . strlen($result_empty) . ")\n";
// 4. Фильтрация с помощью filter_var и удаление знаков
$signed = "Температура: -15°C";
$sanitized = filter_var($signed, FILTER_SANITIZE_NUMBER_INT);
$digits_only_signed = str_replace(['-', '+'], '', $sanitized);
echo "From signed: $digits_only_signed\n";
// 5. Посимвольный обход с ctype_digit (однобайтовая строка)
$str_loop = "Осталось 7 дней";
$res = '';
for ($i = 0; $i < strlen($str_loop); $i++) {
if (ctype_digit($str_loop[$i])) {
$res .= $str_loop[$i];
}
}
echo "Loop result: $res\n";
// 6. Использование preg_match_all для получения массива цифр
$source = "Код: 007, Пин: 1234";
preg_match_all('/\d/', $source, $matches);
$joined = implode('', $matches[0]);
echo "From matches: $joined\n";
// 7. str_replace для известных разделителей
$phone_s = "+1 (800) 555-01-02";
$phone_clean = str_replace(['+','-','(',')',' '], '', $phone_s);
echo "Phone: $phone_clean\n";
// 8. Использование intval (не рекомендуется для извлечения всех цифр)
$test_intval = "2019 год";
echo "intval: " . intval($test_intval) . "\n"; // 2019
$test_intval2 = "год 2019";
echo "intval2: " . intval($test_intval2) . "\n"; // 0
// 9. С помощью array_filter и str_split
$str_split = "a1b2c3d4";
$chars = str_split($str_split);
$digits_arr = array_filter($chars, function($ch) {
return ctype_digit($ch);
});
$result_filter = implode('', $digits_arr);
echo "Filter: $result_filter\n";
// 10. Регулярное выражение с захватом только групп цифр (альтернатива)
$text_groups = "ID: 12345, Pass: 67890";
preg_match_all('/\d+/', $text_groups, $groups);
$all_numbers = implode('', $groups[0]);
echo "Groups: $all_numbers\n";
?>
Unicode: 421000 Mixed: 123456 Empty result: '' (длина 0) From signed: 15 Loop result: 7 From matches: 0071234 Phone: 18005550102 intval: 2019 intval2: 0 Filter: 1234 Groups: 1234567890