Работа с фрагментами строк в PHP: от базовых функций до продвинутых техник

Раздел: Программирование на PHP -> Строки и массивы в PHP

Основные методы извлечения подстроки

Какая функция является базовой для получения подстроки?

substr() – стандартная функция PHP для извлечения части строки. Принимает три параметра: исходную строку, начальную позицию (с нуля) и длину (опционально). Если длина не указана, возвращается все до конца строки.

$str = 'Привет, мир!';
echo substr($str, 0, 6); // "Привет"
echo substr($str, 8);    // "мир!"

Отрицательные значения start отсчитывают от конца строки. Отрицательная length также работает.

echo substr($str, -4, 2); // "ми"

Типичные ошибки:

  • Если start больше длины строки, substr возвращает пустую строку (до PHP 8.0 – false в некоторых случаях).
  • При работе с многобайтовыми кодировками (UTF-8) substr оперирует байтами, а не символами. Для кириллицы это приводит к некорректному результату.

Как правильно извлечь подстроку из UTF-8 строки?

Используйте mb_substr() – аналог substr с поддержкой кодировок. Необходимо указать кодировку третьим параметром (по умолчанию UTF-8, если настроена директива mb_internal_encoding).

$str = 'Привет, мир!';
echo mb_substr($str, 0, 6, 'UTF-8'); // "Привет"
echo mb_substr($str, 8, null, 'UTF-8'); // "мир!"

Без указания кодировки или при неверной кодировке mb_substr также может давать сбои. Убедитесь, что расширение mbstring включено.

Как получить один символ из строки по индексу?

Строку можно рассматривать как массив символов (байтов). Обращение по квадратным скобкам $str[$index] возвращает один символ (байт). Для UTF-8 это опасно.

$str = 'Hello';
echo $str[0]; // "H"
echo $str[-1]; // "o" (PHP 7.1+)
$str2 = 'Привет';
echo $str2[0]; // выведет первый байт, не "П"

Ошибка: попытка доступа к несуществующему индексу (больше длины) вызовет warning и вернет пустую строку. Для многобайтовых строк используйте mb_substr($str, 0, 1).

Как извлечь часть строки после определенного символа или слова?

Функция strstr() (или strchr) находит первое вхождение подстроки и возвращает все после неё (включая саму подстроку, если третий параметр true – вернет до неё).

$email = 'user@example.com';
echo strstr($email, '@');   // "@example.com"
echo strstr($email, '@', true); // "user"
// Альтернатива: strpos + substr
$pos = strpos($email, '@');
echo substr($email, $pos + 1); // "example.com"

Если подстрока не найдена, strstr возвращает false. Это может привести к ошибке при выводе. Проверяйте с помощью строгого сравнения.

Как извлечь фрагмент между двумя разделителями?

Комбинация explode(), array_slice() или использование регулярных выражений.

$str = 'начало|фрагмент|конец';
$parts = explode('|', $str);
echo $parts[1]; // "фрагмент"
// Если нужно несколько элементов:
$middle = array_slice($parts, 1, -1);
print_r($middle); // Array([0] => фрагмент)

Проблемы: explode создает массив, что может быть неэффективно для больших строк; регулярные выражения (preg_match) могут быть избыточны, но гибче.

Расширенные примеры работы с подстроками

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

Извлечение домена из email с конца

Используем strrpos() для поиска последней точки и substr().

Пример
$email = 'user@mail.example.com';
$lastDot = strrpos($email, '.');
$domain = substr($email, $lastDot + 1);
echo $domain; // "com"
// Если нужно извлечь домен верхнего уровня вместе с предшествующей частью:
$domainParts = explode('.', $email);
$tld = end($domainParts);
$sld = prev($domainParts);
echo "$sld.$tld"; // "example.com"
com
example.com

Обрезка строки до заданной длины с многоточием

Для сокращения длинного текста (например, для превью). Учитываем многобайтовость.

Пример
function truncate($text, $maxLength = 100, $ellipsis = '...') {
    if (mb_strlen($text) <= $maxLength) {
        return $text;
    }
    return mb_substr($text, 0, $maxLength - mb_strlen($ellipsis)) . $ellipsis;
}

$longText = 'Это очень длинная строка, содержащая много символов, включая русские буквы и эмодзи ?';
echo truncate($longText, 20);
// Результат: "Это очень длинная..."
Это очень длинная...

Извлечение имени файла из пути без расширения

Комбинируем basename() и strrpos().

Пример
$path = '/var/www/html/index.html';
$base = basename($path); // "index.html"
$dotPos = strrpos($base, '.');
if ($dotPos !== false) {
    $filename = substr($base, 0, $dotPos);
} else {
    $filename = $base;
}
echo $filename; // "index"
index

Извлечение подстроки с помощью регулярного выражения

Функция preg_match() позволяет извлечь часть строки по сложному шаблону.

Пример
$str = 'Заказ №12345 от 01.02.2023';
$pattern = '/№(\d+)/';
if (preg_match($pattern, $str, $matches)) {
    echo $matches[1]; // "12345"
}
// Извлечение даты
$datePattern = '/(\d{2}\.\d{2}\.\d{4})/';
preg_match($datePattern, $str, $dateMatches);
echo $dateMatches[1]; // "01.02.2023"
12345
01.02.2023

Замена части строки с сохранением остального (substr_replace)

substr_replace() заменяет фрагмент строки на другой, не изменяя длину (кроме случая, когда новый фрагмент другой длины).

Пример
$str = 'Привет, мир!';
$newStr = substr_replace($str, 'PHP', 8, 3); // заменим "мир" на "PHP"
echo $newStr; // "Привет, PHP!"
// Удаление части: пустая строка
$removed = substr_replace($str, '', 0, 7); // удалим "Привет,"
echo $removed; // " мир!"
Привет, PHP!
 мир!

Работа с отрицательными индексами в substr

Отрицательный start отсчитывает символы с конца, отрицательная length также возможна (но ведет себя неочевидно).

Пример
$str = '123456789';
echo substr($str, -4);     // "6789"
echo substr($str, -4, 2);  // "67"
echo substr($str, 2, -3);  // "3456" – длина от 2 до конца минус 3 символа
6789
67
3456

Сравнение производительности substr и mb_substr для латиницы

Если строка гарантированно однобайтовая (латиница, цифры), substr быстрее.

Пример
$start = microtime(true);
for ($i = 0; $i < 100000; $i++) {
    substr('Hello World', 0, 5);
}
echo 'substr: ' . (microtime(true) - $start) . "\n";

$start = microtime(true);
for ($i = 0; $i < 100000; $i++) {
    mb_substr('Hello World', 0, 5, 'UTF-8');
}
echo 'mb_substr: ' . (microtime(true) - $start);
substr: 0.0045
mb_substr: 0.0121

Обработка эмодзи и суррогатных пар

Эмодзи занимают 2 или 4 байта, но mb_substr корректно обрабатывает их при указании UTF-8.

Пример
$emojiStr = 'Привет ? мир!';
echo mb_substr($emojiStr, 7, 1, 'UTF-8'); // "?"
echo substr($emojiStr, 7, 2); // скорее всего сломает эмодзи
?
?? или непонятные байты

Примечание:

Для работы с многобайтовыми строками всегда используйте функции mb_*, а также проверяйте, что кодировка внутреннего представления соответствует ожидаемой (обычно UTF-8).

Часть строки в PHP - comments

En
Php часть (php)