Как обрезать строку в PHP без повреждения кириллицы

Для обрезки кириллицы в PHP используйте mb_substr() с кодировкой UTF-8. Функция substr() считает байты и может разрезать русскую букву. Чтобы добавить многоточие, сначала сравните длину текста с лимитом. Примеры помогут обрезать текст по символам, словам и разделителям, а также подготовить анонс в WordPress.

ФункцияЕдиница отсчетаОбрезка до словаМноготочие автоматическиСреда примеров
substr()БайтыНетНетPHP 8.x
mb_substr()СимволыНетНетPHP 8.x, mbstring
mb_strcut()Байты, с сохранением границ символовНетНетPHP 8.x, mbstring
mb_strimwidth()Условная ширина отображенияНетДа, если передать маркерPHP 8.x, mbstring
mb_strrpos()Позиция в символахЧерез поиск пробелаНетPHP 8.x, mbstring
preg_match()В режиме u точка соответствует символу UTF-8Зависит от шаблонаНетPHP 8.x
mb_str_split()СимволыНетНетPHP 8.x, mbstring; функция доступна с PHP 7.4
wp_trim_words()Слова; поведение зависит от локали WordPressДа, в режиме подсчета словДаWordPress
Содержание

Как подготовить и запустить примеры

Сохраните файл example.php в кодировке UTF-8. Начните файл с <?php, затем вставьте выбранный пример. Если PHP установлен, запустите файл командой php example.php из его каталога.

Функции с префиксом mb_ требуют расширения mbstring. Команда php -m покажет список подключенных расширений: найдите в нем mbstring. В примерах кодировка передается явно, поэтому настройки сервера не меняют результат.

Все функции обрезки здесь возвращают обычный текст. Перед выводом пользовательского текста в HTML экранируйте результат через htmlspecialchars().

Не обрезайте HTML-разметку вместе с тегами: граница среза может попасть внутрь тега или сущности.

Как посчитать количество символов в строке PHP

Функция strlen() возвращает длину строки в байтах. Для количества символов используйте mb_strlen() с указанием кодировки.

$text = 'Привет';
echo strlen($text), PHP_EOL;
echo mb_strlen($text, 'UTF-8');

На отдельных строках появятся 12 и 6. Каждая буква этого русского слова занимает 2 байта в UTF-8.

Пробелы и переводы строк тоже входят в длину текста.

При этом mb_strlen() считает кодовые точки Unicode. Составной эмодзи или буква с отдельным диакритическим знаком могут включать несколько точек. Для пользовательских символов такого типа подходят функции grapheme_* расширения intl.

Чем отличаются substr(), mb_substr() и mb_strcut() на кириллице

substr() отрезает заданное количество байтов без учета кодировки. mb_substr() отсчитывает символы, а mb_strcut() соблюдает байтовый лимит, сохраняя целые символы.

$text = 'Привет';
echo bin2hex(substr($text, 0, 3)), PHP_EOL;
echo mb_substr($text, 0, 3, 'UTF-8'), PHP_EOL;
echo mb_strcut($text, 0, 3, 'UTF-8');

Пример напечатает d09fd1, При и П на отдельных строках.

Первый результат показан в шестнадцатеричном виде через bin2hex(). Байты d09f кодируют букву «П», а d1 остается незавершенным началом следующей буквы. Если вывести такой срез напрямую, текст потеряет корректность UTF-8.

Для анонсов и подписей выбирайте mb_substr().

Функция mb_strcut() нужна, когда ограничение задано именно в байтах.

Как обрезать строку до N символов с многоточием

Функция mb_substr() возвращает подстроку на основе количества символов. Позиция обрезки отсчитывается от начала строки. Позиция первого символа равна 0.

Обертка truncate_chars() включает многоточие в общий лимит. Короткая строка остается без изменений. Если лимит меньше длины маркера, функция обрезает сам маркер.

function truncate_chars(string $text, int $limit, string $marker = '…'): string
{
    if ($limit <= 0) {
        return '';
    }
    if (mb_strlen($text, 'UTF-8') <= $limit) {
        return $text;
    }
    $markerLength = mb_strlen($marker, 'UTF-8');
    if ($markerLength >= $limit) {
        return mb_substr($marker, 0, $limit, 'UTF-8');
    }
    $prefix = mb_substr($text, 0, $limit - $markerLength, 'UTF-8');
    return rtrim($prefix) . $marker;
}

echo truncate_chars('Привет, мир!', 8), PHP_EOL;
echo truncate_chars('Привет', 8), PHP_EOL;
echo truncate_chars('Привет', 2, '...');

Три вызова вернут Привет,…, Привет и ... Каждый результат появится на отдельной строке.

Первая строка содержит 8 символов вместе с многоточием.

Функция rtrim() убирает обычные конечные пробелы перед маркером. Поэтому результат иногда получается короче лимита.

Как mb_strimwidth() ограничивает ширину текста

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

echo mb_strimwidth('Привет, мир!', 0, 8, '…', 'UTF-8'), PHP_EOL;
echo mb_strimwidth('Привет', 0, 8, '…', 'UTF-8');

Длинная строка превратится в Привет,…. Следом появится короткая строка Привет без многоточия.

Функция считает полуширинные символы за 1 единицу, полноширинные – за 2. Поэтому ограничение ширины не всегда совпадает с ограничением количества символов.

Это не измерение текста в пикселях: функция не учитывает шрифт браузера.

Если ограничение задано количеством символов, используйте mb_substr(). Для смешанного текста с ограничением условной ширины подойдет mb_strimwidth(). Передавайте положительную ширину.

Как обрезать текст до целого слова через mb_strrpos()

Функция strrpos() находит позицию последнего вхождения подстроки в строке. Для символьных позиций в UTF-8 используйте mb_strrpos(). Так поиск пробела согласуется с последующим вызовом mb_substr().

Функция truncate_at_space() ищет последний обычный пробел в доступном фрагменте. Если пробела нет, она обрезает длинное слово по символам. Многоточие входит в общий лимит.

function truncate_at_space(string $text, int $limit, string $marker = '…'): string
{
    $text = trim($text);
    if ($limit <= 0) {
        return '';
    }
    if (mb_strlen($text, 'UTF-8') <= $limit) {
        return $text;
    }
    $budget = $limit - mb_strlen($marker, 'UTF-8');
    if ($budget <= 0) {
        return mb_substr($marker, 0, $limit, 'UTF-8');
    }
    $window = mb_substr($text, 0, $budget + 1, 'UTF-8');
    $space = mb_strrpos($window, ' ', 0, 'UTF-8');
    $end = ($space === false) ? $budget : $space;
    return rtrim(mb_substr($text, 0, $end, 'UTF-8')) . $marker;
}

echo truncate_at_space('Привет большой мир', 12), PHP_EOL;
echo truncate_at_space('Привет мир дальше', 11), PHP_EOL;
echo truncate_at_space('Приветствие', 6), PHP_EOL;
echo truncate_at_space('Привет', 12);

На отдельных строках появятся Привет…, Привет мир…, Приве… и Привет.

Проверка === false отделяет отсутствие пробела от позиции 0. Дополнительный символ в окне позволяет сохранить слово, которое полностью поместилось перед пробелом.

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

Как обрезать строку регулярным выражением preg_match()

preg_match() позволяет искать границу слова внутри заданного лимита. В шаблоне \b обозначает границу слова; обычная буква b ищет именно букву.

function truncate_regex(string $text, int $limit, string $marker = '…'): string
{
    $text = trim($text);
    if ($limit <= 0) {
        return '';
    }
    if (mb_strlen($text, 'UTF-8') <= $limit) {
        return $text;
    }
    $budget = $limit - mb_strlen($marker, 'UTF-8');
    if ($budget <= 0) {
        return mb_substr($marker, 0, $limit, 'UTF-8');
    }
    $pattern = '/(*UCP)\A.{1,' . $budget . '}\b/su';
    if (preg_match($pattern, $text, $match) === 1) {
        return rtrim($match[0]) . $marker;
    }
    return mb_substr($text, 0, $budget, 'UTF-8') . $marker;
}

echo truncate_regex('Привет большой мир', 12), PHP_EOL;
echo truncate_regex('Приветствие', 6);

Первый вызов напечатает Привет…, второй – Приве… на следующей строке.

  • \A привязывает совпадение к началу строки.
  • . обозначает любой символ; модификатор s включает DOTALL, поэтому точка захватывает и перевод строки.
  • {1,N} ограничивает количество захваченных символов.
  • u включает обработку UTF-8, а (*UCP) задает Unicode-свойства для классов вроде \w и границ \b.

Граница слова может проходить рядом со знаком пунктуации. Если задача требует разделения только по пробелам, выбирайте truncate_at_space().

Оба примера рассчитаны на корректный входной UTF-8.

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

Для русского текста разбивайте строку через preg_split() с модификатором u. Функция str_word_count() без дополнительной настройки не подходит для подсчета кириллических слов.

function truncate_words(string $text, int $limit, string $marker = '…'): string
{
    if ($limit <= 0) {
        return '';
    }
    $words = preg_split('/\s+/u', trim($text), -1, PREG_SPLIT_NO_EMPTY);
    $result = implode(' ', array_slice($words, 0, $limit));
    return $result . (count($words) > $limit ? $marker : '');
}

echo truncate_words('Один два три четыре пять', 3), PHP_EOL;
echo truncate_words('Один два', 3);

Длинный текст сократится до Один два три…. Короткий останется без маркера: Один два.

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

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

Для первого символа задайте начало 0 и длину 1. Отрицательная длина исключает символы с конца строки. Отрицательное начало отсчитывает позицию от конца.

Получить или удалить первый символ строки

$text = 'Привет';
echo mb_substr($text, 0, 1, 'UTF-8'), PHP_EOL;
echo mb_substr($text, 1, null, 'UTF-8');

Пример выведет П и ривет на отдельных строках. Вторая операция возвращает строку со второго символа до конца.

Удалить последний символ строки в PHP

$text = 'Привет';
echo mb_substr($text, 0, -1, 'UTF-8'), PHP_EOL;
echo substr('Привет!', 0, -1);

После удаления последнего символа получатся Приве и Привет на отдельных строках.

Второй пример безопасен, потому что последний знак ! занимает 1 байт. Вызов substr($text, 0, -1) на слове «Привет» повредит последнюю букву.

Для произвольного текста UTF-8 удаляйте символ через mb_substr().

Удалить конкретные знаки с конца через rtrim()

echo rtrim('Привет!!!', '!');

Функция удалит все конечные восклицательные знаки и напечатает Привет.

Второй аргумент rtrim() задает набор удаляемых байтов, а не одну подстроку. Не используйте его для удаления русской буквы или точного суффикса. Для удаления ровно одного последнего символа подойдет mb_substr().

Вырезать часть строки с конца

echo mb_substr('Привет, мир', -3, 3, 'UTF-8');

В результате вы получите мир. Начало -3 указывает на третий символ с конца.

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

strstr() с третьим аргументом true возвращает текст перед первым разделителем. Если разделителя нет, функция возвращает false. Обработайте этот результат явно, чтобы сохранить исходный текст.

$text = 'Москва: прогноз погоды';
$before = strstr($text, ':', true);
echo $before === false ? $text : $before;

Функция вернет текст Москва перед двоеточием. Разделителем может быть и подстрока, например ' – '.

Для простого разделения удобно использовать explode() с лимитом 2. Первый элемент существует даже при отсутствии разделителя.

echo explode(':', 'Москва: прогноз погоды', 2)[0], PHP_EOL;
echo explode(':', 'Москва', 2)[0];

Оба вызова напечатают Москва на отдельных строках, хотя во второй строке двоеточия нет.

Если вам нужна позиция разделителя, используйте strpos() вместе с substr(). Обе функции считают байты, поэтому их позиции согласованы.

$text = 'Москва: прогноз погоды';
$position = strpos($text, ':');
echo $position === false ? $text : substr($text, 0, $position);

Этот способ тоже вернет Москва. Срез заканчивается перед найденным разделителем и сохраняет целые буквы.

Не передавайте байтовую позицию из strpos() в mb_substr(): эта функция ожидает позицию в символах.

Когда нужны mb_str_split(), wordwrap() и strtok()

Для обычного анонса достаточно mb_substr(). Разбиение на массив или строки полезно, когда вы дальше обрабатываете отдельные фрагменты.

Разбить UTF-8 на фрагменты через mb_str_split()

Функция называется str_split(), с подчеркиванием. Она разбивает строку по байтам. Для кириллицы используйте mb_str_split(), доступную с PHP 7.4.

$parts = mb_str_split('Привет мир', 6, 'UTF-8');
echo rtrim($parts[0] ?? '') . (isset($parts[1]) ? '…' : ''), PHP_EOL;
$parts = mb_str_split('Привет', 6, 'UTF-8');
echo rtrim($parts[0] ?? '') . (isset($parts[1]) ? '…' : '');

В первой строке появится Привет…, во второй – Привет.

Здесь лимит 6 относится только к фрагменту без многоточия. Проверка isset() защищает обращение ко второму элементу короткого массива.

Для длинного текста такой подход создает лишние фрагменты, поэтому для одного среза выбирайте mb_substr().

Почему wordwrap() не подходит для символьного лимита кириллицы

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

В коде переноса строки пишите "\n" в двойных кавычках. Строка "n" содержит обычную латинскую букву.

Для безопасной обрезки кириллицы по словам используйте truncate_at_space() или truncate_words().

Получить первую готовую строку через strtok()

strtok() выделяет фрагменты по разделителям, но не ограничивает количество символов. Функция подходит для извлечения первой непустой строки из уже разделенного текста.

$text = "Привет\nБольшой мир";
$first = strtok($text, "\n");
echo $first === false ? '' : $first;

Пример напечатает Привет. Функция пропускает начальные разделители, поэтому результатом будет первый непустой фрагмент. Связка с wordwrap() не делает байтовый подсчет безопасным для кириллицы.

Обрезка слов в WordPress

Внутри загруженного WordPress используйте wp_trim_words(). Второй аргумент задает количество слов, третий – конечный маркер. Для анонса из 20 слов передайте wp_trim_words($text, 20, '…').

$text = '<p>Привет большой мир</p>';
echo esc_html(wp_trim_words($text, 20, '…')), PHP_EOL;
echo esc_html(wp_trim_words($text, 2, '…'));

В русской локали без изменяющих результат фильтров появятся две строки: Привет большой мир и Привет большой….

Функция сама вызывает wp_strip_all_tags() перед обрезкой. Дополнительно удалять теги тем же вызовом не нужно.

Очистка тегов не заменяет экранирование: для вывода обычного текста в HTML пример использует esc_html().

Какую функцию выбрать для обрезки строки

  • Для точного количества символов UTF-8 берите mb_substr() и mb_strlen().
  • Для условной ширины смешанного текста используйте mb_strimwidth().
  • Для целых слов внутри символьного лимита ищите пробел через mb_strrpos().
  • Для первых N слов разбивайте текст через preg_split('/\s+/u').
  • Для среза перед разделителем используйте strstr() или explode().
  • Для анонса в WordPress выбирайте wp_trim_words().

В примерах знак … занимает 1 символ. Три точки ... занимают 3 символа.

HTML-сущность &hellip; браузер показывает как многоточие, но до декодирования PHP считает ее буквальной последовательностью знаков. Добавляйте обычное многоточие перед экранированием результата.

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

Комментарии

Оставьте свой комментарий
Пока никто не оставил комментариев