📑 Содержание
Введение
Поиск подстроки в строке — одна из самых частых операций в программировании. В PHP для этого существует целый арсенал функций, каждая из которых решает свою задачу. В этой статье мы разберем все методы из официальной документации php.net: от классического strpos до мультибайтовых функций и регулярных выражений.
strpos и stripos — позиция первого вхождения
Функция strpos() ищет первое вхождение подстроки и возвращает её позицию (число, начиная с 0) или false, если подстрока не найдена.
$string = "Привет, мир! Как дела?";
// Поиск "мир" в строке
$pos = strpos($string, "мир");
var_dump($pos); // int(9)
// Подстрока не найдена
$pos = strpos($string, "вселенная");
var_dump($pos); // bool(false)
Критическая ошибка при использовании strpos
Позиция 0 — это валидный результат (подстрока найдена в начале строки), но 0 == false в PHP. Поэтому проверку нужно делать строго через ===:
// НЕПРАВИЛЬНО
if (strpos($string, "Привет")) {
echo "Найдено";
}
// Не сработает, если подстрока в начале строки (позиция 0)
// ПРАВИЛЬНО
if (strpos($string, "Привет") !== false) {
echo "Найдено";
}
Поиск с указанной позиции
Третий параметр $offset позволяет начать поиск с определенной позиции.
$string = "один два три два один";
// Начать поиск с позиции 5 (пропустить первое "два")
$pos = strpos($string, "два", 5);
var_dump($pos); // int(14) — второе вхождение
stripos — поиск без учета регистра
Функция stripos() работает идентично strpos, но игнорирует регистр символов.
$string = "Привет, Мир!";
$pos = strpos($string, "мир"); // false — регистр важен
$pos = stripos($string, "мир"); // int(9) — регистр игнорируется
strrpos и strripos — позиция последнего вхождения
Функция strrpos() ищет последнее вхождение подстроки и возвращает его позицию.
💡 Доступность strripos: PHP 5+
$string = "один два три два один";
$pos = strrpos($string, "два");
var_dump($pos); // int(14) — последнее вхождение
Эти функции полезны, когда нужно найти последнее расширение файла или последний разделитель:
$filename = "document.backup.tar.gz";
$pos = strrpos($filename, ".");
$extension = substr($filename, $pos + 1); // "gz"
str_contains — простая проверка наличия подстроки
До PHP 8.0 для проверки наличия подстроки использовали конструкцию strpos() !== false. В PHP 8.0 появилась функция str_contains(), которая возвращает true или false.
$string = "PHP — это язык программирования";
var_dump(str_contains($string, "язык")); // bool(true)
var_dump(str_contains($string, "Python")); // bool(false)
var_dump(str_contains($string, "")); // bool(true) — пустая строка всегда содержится
Когда использовать str_contains, а когда strpos
Используйте str_contains, если вам нужно только проверить наличие подстроки. Используйте strpos, если вам нужна позиция вхождения.
// Только проверка — str_contains (PHP 8.0+)
if (str_contains($email, "@")) {
echo "Корректный email";
}
// Нужна позиция — strpos (PHP 4+)
$pos = strpos($email, "@");
$domain = substr($email, $pos + 1);
strstr, stristr, strchr, strrchr — извлечение подстроки
Эти функции не просто находят подстроку, а возвращают часть строки начиная с найденного вхождения.
strstr и strchr
strstr() возвращает часть строки от первого вхождения и до конца. strchr() — это псевдоним (alias) функции strstr().
💡 Доступность strchr: PHP 4+ (псевдоним)
$email = "user@example.com";
$domain = strstr($email, "@");
var_dump($domain); // string(12) "@example.com"
Параметр $before_needle
Четвертый параметр $before_needle = true возвращает часть строки ДО вхождения.
$email = "user@example.com";
$user = strstr($email, "@", true);
var_dump($user); // string(4) "user"
stristr — без учета регистра
stristr() работает как strstr, но игнорирует регистр.
$string = "Hello World";
$result = stristr($string, "WORLD");
var_dump($result); // string(5) "World"
strrchr — от последнего вхождения
strrchr() возвращает часть строки от последнего вхождения символа.
$path = "/var/www/html/index.php";
$filename = strrchr($path, "/");
var_dump($filename); // string(10) "/index.php"
strrchr ищет одиночный символ, а не подстроку. Если передать строку длиннее одного символа, используется только первый символ.
substr_count — подсчет количества вхождений
Функция substr_count() подсчитывает, сколько раз подстрока встречается в строке.
$text = "Мама мыла раму. Мама любит раму.";
$count = substr_count($text, "Мама");
var_dump($count); // int(2)
Параметры $offset и $length
Можно указать смещение и длину области поиска.
$text = "Мама мыла раму. Мама любит раму.";
// Искать только в первых 20 символах
$count = substr_count($text, "раму", 0, 20);
var_dump($count); // int(1)
Важная особенность
substr_count не учитывает пересекающиеся вхождения:
$string = "aaa";
$count = substr_count($string, "aa");
var_dump($count); // int(1), а не 2
Мультибайтовые версии (mb_*)
Все вышеперечисленные функции работают с однобайтовыми кодировками (ASCII, Latin-1). Для UTF-8, кириллицы и других многобайтовых кодировок нужно использовать функции с префиксом mb_:
| Однобайтовая | Мультибайтовая | Описание | Доступность mb_* |
|---|---|---|---|
strpos() |
mb_strpos() |
Позиция первого вхождения | PHP 4.0.6+ |
stripos() |
mb_stripos() |
Позиция без учета регистра | PHP 5.2+ |
strrpos() |
mb_strrpos() |
Позиция последнего вхождения | PHP 4.0.6+ |
strripos() |
mb_strripos() |
Последнее без учета регистра | PHP 5.2+ |
strstr() |
mb_strstr() |
Часть от первого вхождения | PHP 4.0.6+ |
stristr() |
mb_stristr() |
То же без учета регистра | PHP 4.0.6+ |
strrchr() |
mb_strrchr() |
Часть от последнего вхождения | PHP 4.0.6+ |
substr_count() |
mb_substr_count() |
Подсчет вхождений | PHP 4.3+ |
Почему это важно
$string = "Привет мир";
// Обычная strpos считает байты, а не символы
$pos = strpos($string, "мир");
var_dump($pos); // int(13) — неверно для UTF-8
// mb_strpos считает символы
$pos = mb_strpos($string, "мир");
var_dump($pos); // int(7) — верно
Указание кодировки
Мультибайтовые функции принимают параметр кодировки:
$pos = mb_strpos($string, "мир", 0, "UTF-8");
Начиная с PHP 8.0, кодировку можно задать глобально через mb_internal_encoding(), и параметр можно опускать.
Регулярные выражения: preg_match и preg_match_all
Когда нужно искать по шаблону, а не по точной подстроке, используются функции регулярных выражений.
preg_match — поиск первого совпадения
$text = "Заказ №12345 оформлен 01.01.2024";
// Найти все цифры
if (preg_match("/\d+/", $text, $matches)) {
var_dump($matches[0]); // string(5) "12345"
}
// Найти дату в формате ДД.ММ.ГГГГ
if (preg_match("/(\d{2})\.(\d{2})\.(\d{4})/", $text, $matches)) {
var_dump($matches[0]); // string(10) "01.01.2024"
var_dump($matches[1]); // string(2) "01" — день
var_dump($matches[2]); // string(2) "01" — месяц
var_dump($matches[3]); // string(4) "2024" — год
}
preg_match_all — поиск всех совпадений
$text = "Яблоки: 5, Груши: 3, Апельсины: 8";
preg_match_all("/(\d+)/", $text, $matches);
var_dump($matches[0]); // array(3) { [0]=>"5", [1]=>"3", [2]=>"8" }
Поиск с точным совпадением через регулярки
Если нужен поиск точной подстроки, но с использованием регулярных выражений, используйте preg_quote() для экранирования спецсимволов.
$needle = "цена: 100 руб.";
$pattern = "/" . preg_quote($needle, "/") . "/";
if (preg_match($pattern, $text)) {
echo "Найдено";
}
Сравнительная таблица: что когда использовать
| Задача | Функция | Мин. версия PHP | Пример |
|---|---|---|---|
| Проверить наличие подстроки | str_contains() |
PHP 8.0 | str_contains($s, "abc") |
| Проверить наличие (PHP 7 и ниже) | strpos() !== false |
PHP 4 | strpos($s, "abc") !== false |
| Позиция первого вхождения | strpos() |
PHP 4 | strpos($s, "abc") |
| Позиция без учета регистра | stripos() |
PHP 5 | stripos($s, "abc") |
| Позиция последнего вхождения | strrpos() |
PHP 4 | strrpos($s, "abc") |
| Извлечь часть от вхождения | strstr() |
PHP 4 | strstr($email, "@") |
| Извлечь часть до вхождения | strstr($s, $n, true) |
PHP 5.3 | strstr($email, "@", true) |
| Извлечь без учета регистра | stristr() |
PHP 4 | stristr($s, "abc") |
| Извлечь от последнего вхождения | strrchr() |
PHP 4 | strrchr($path, "/") |
| Подсчитать вхождения | substr_count() |
PHP 4 | substr_count($s, "abc") |
| Подсчитать с ограничением области | substr_count($s, $n, $o, $l) |
PHP 5.1 | substr_count($s, "a", 0, 10) |
| Поиск по шаблону | preg_match() |
PHP 4 | preg_match("/\d+/", $s) |
| Найти все совпадения | preg_match_all() |
PHP 4 | preg_match_all("/\d+/", $s) |
| Работа с UTF-8 (позиция) | mb_strpos() |
PHP 4.0.6 | mb_strpos($s, "мир") |
| Работа с UTF-8 (без регистра) | mb_stripos() |
PHP 5.2 | mb_stripos($s, "мир") |
| Работа с UTF-8 (последняя позиция) | mb_strrpos() |
PHP 4.0.6 | mb_strrpos($s, "мир") |
| Работа с UTF-8 (подсчет) | mb_substr_count() |
PHP 4.3 | mb_substr_count($s, "мир") |
Типичные ошибки и нюансы
Ошибка 1: Нестрогое сравнение с false
// НЕПРАВИЛЬНО
if (strpos($string, $needle)) { ... }
// ПРАВИЛЬНО
if (strpos($string, $needle) !== false) { ... }
// ЕЩЕ ЛУЧШЕ (PHP 8.0+)
if (str_contains($string, $needle)) { ... }
Ошибка 2: Использование однобайтовых функций с UTF-8
$string = "Привет";
// strlen вернет 12 (6 символов × 2 байта)
echo strlen($string); // 12
// mb_strlen вернет 6
echo mb_strlen($string); // 6
Ошибка 3: Поиск пустой строки
// strpos всегда вернет 0 для пустой строки
var_dump(strpos("текст", "")); // int(0)
// str_contains всегда вернет true (PHP 8.0+)
var_dump(str_contains("текст", "")); // bool(true)
Ошибка 4: Регистрозависимость по умолчанию
$string = "PHP";
var_dump(str_contains($string, "php")); // false (PHP 8.0+)
var_dump(stripos($string, "php") !== false); // true
Для регистронезависимой проверки в PHP 8+ нет прямой функции str_icontains, поэтому используйте stripos:
function str_icontains(string $haystack, string $needle): bool {
return stripos($haystack, $needle) !== false;
}
Производительность
Для простых задач поиска точной подстроки используйте строковые функции (strpos, str_contains) — они работают быстрее регулярных выражений.
preg_match стоит использовать только тогда, когда нужен поиск по шаблону. Для поиска точной подстроки через регулярки не забудьте про preg_quote.
Относительная скорость (от быстрого к медленному)
str_contains/strpos— самые быстрыеmb_strpos— чуть медленнее из-за обработки многобайтовых символовpreg_match— самый медленный, но самый гибкий
Заключение
В PHP есть полный набор инструментов для поиска подстроки в строке. Выбор конкретной функции зависит от задачи:
- Нужно просто проверить наличие? Используйте
str_contains(PHP 8.0+) илиstrpos !== false(PHP 4+). - Нужна позиция? Используйте
strpos(PHP 4+) илиstrrpos(PHP 4+). - Нужно извлечь часть строки? Используйте
strstr(PHP 4+) илиstrrchr(PHP 4+). - Работаете с UTF-8? Используйте мультибайтовые версии
mb_*(PHP 4.0.6+). - Нужен поиск по шаблону? Используйте
preg_match(PHP 4+) илиpreg_match_all(PHP 4+).