Чтобы разобраться в этом вопросе, нам для начала необходимо понять, что мы подразумеваем под «Правильно обрезать строку».
Я не буду писать здесь 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 байт.