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

3

Чтобы разобраться в этом вопросе, нам для начала необходимо понять, что мы подразумеваем под «Правильно обрезать строку».

Я не буду писать здесь SEO текст, поэтому сразу перейду к делу. Когда я искал готовое решение этой проблемы (и не только я один :)), то набрел на простой способ, который режет строку с указанным количеством символов. Вроде удобно, что еще нужно? Но как оказалось, все не так просто и вот почему.

Есть такая функция, при помощи которой мы будем считать кол-во символов в обрезаемом тексте. Называется она strlen(). Она и вправду считает, но только не символы, а байты. Это очень важно. Поскольку, если у нас латиница кодируется в один байт, то с кириллицей сложнее — в 2 байта. И все бы ничего, если бы у нас был текст только латиницей писан.

Но часто, да что там часто — почти всегда(!) в нашем кириллическом тексте встречаются латинские слова: будь-то названия компаний, функций, терминов и много другого. И тогда весь наш подсчет символов строки становится каким-то сумасшествием. Чтобы было понятней, я приведу простой пример:

echo strlen('Ваша функция не работает'); # выведет 45 символов, хотя символов по факту - 24

echo strlen('Your function is not working'); # выведет 28 символов, по факту символов - 28

echo strlen('Ваша функция is not working'); # выведет 38 символов, хотя по факту символов - 27

Поэтому для того, чтобы нам это побороть, я приведу рабочую функцию, которая сначала берет весь текст, кодирует его в windows-1251, считает кол-во символов и, если надо — обрезает строку добавляя троеточие в конце и кодирует обратно в UTF-8. Покажу как это работает на примере:

function crop_text($text, $num) {
        $text = strip_tags($text); #удаляем все html теги
        $text = str_replace(' ', ' ', $text); #заменяем   на пробел
        $text = iconv('utf-8', 'windows-1251', $text); #кодируем в win-1251
        if (strlen($text) > $num) { #strlen считает кол-во символов и, если оно больше      указанного в переменной $num, то режем ее
            $text = substr($text, 0, $num); #функция substr режет текст от 0 до кол-ва символов в переменной $num
            $text = iconv('windows-1251', 'utf-8', $text); #кодируем обратно в utf-8
            $crop = trim($text) . "..."; #убираем пробел, если он остался после резки и   добавляем троеточие
        } else { #а, если у нас количество символов не больше указанного в переменной $num, то мы кодируем обратно в utf-8
            $text = iconv('windows-1251', 'utf-8', $text);
            $crop = $text;
        }

        return $crop;
    }

Эта функция полностью рабочая и, что важно, не оставляет в конце обрезанной строки знаки вопроса или другие не понятные символы. Кстати, они появляются тогда, когда мы режем кириллицу по пополам. То есть кириллическая буква «а» = 2 байта, но если так получается, что скрипт ее режет пополам (ведь он у нас считает не символы, а байты), то у нас остается от «а» всего 1 байт, поэтому и выводятся всякие непонятные символы.

Еще стоит отметить, что пробел, как полноправный символ тоже имеет 1 байт.