Блог \ Возможные ошибки \ Проблема в substr() и utf-8

Проблема с обрезанием строки в кодировке utf-8

Иногда случается так, что при обрезке строки с помощью функции substr() в кодировке utf-8 в конце обрезанной строки появляется непонятный символ:

Например:

<?

$stroka = 'Строка которую мы будем резать';

echo  substr($stroka,0,40);

В результате:  Строка которую мы буд?

?>

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

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

Fatal error: Call to undefined function mb_substr() in Z:\home\www\makannikov.ru\blog.php on line 85

Я несколько часов искал ответ на этот вопрос, но ничего так и не нашел. А оказалось все проще простого!

Я решил реализовать решение этой проблемы изменив кодировку строки перед обрезкой, затем обрезать и вернуть назад в кодировку utf-8.

<?
$
stroka = iconv('UTF-8','windows-1251',$stroka ); //Меняем кодировку на windows-1251

$stroka = substr($stroka ,0,40); //Обрезаем строку

$stroka = iconv('windows-1251','UTF-8',$stroka ); //Возвращаем кодировку в utf-8

echo $stroka;

?>

В результате: Строка которую мы буд

 

 

Дополнение к статье от 24.03.2012г

Собственная функция substr()

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

<?

//Назовем функцию "substr_function" - вы можете придумать свое название

 

function substr_function($stroka,$chislo)
// $stroka - это текст который будем обрезать
// $chislo - это количество символов, котрое должно остаться при обрезании строки
{
    // Если число символов которое мы задаем переменной $chislo меньше чем количество символов в тексте $stroka, то начинаем выполнять следующее...
    if($chislo < strlen($stroka)) //strlen() - эта функция возвращает кол-во символов в строке
    {
        $stroka = iconv('UTF-8','windows-1251',$stroka ); //Меняем кодировку на windows-1251

        $stroka = substr($stroka ,0,$chislo); //Обрезаем строку

        $stroka = iconv('windows-1251','UTF-8',$stroka ); //Возвращаем кодировку в utf-8
       
        //Добавим троеточие после обрезанного текста

        $stroka .='...';

    }
    return $stroka;
}

?>

Как использовать функцию: substr_function(Сюда вставляем текст или переменную содержащую текст,60)

 

Например:

<?

      echo substr_function('Если ввести сюда текст, то функция обрежет его и подставит вконце троеточие',22)

?>

Результат: Если ввести сюда текст...

 

Вот и все, как видите многие вещи в PHP можно обходить легкими путями!

Метки: substr(), php, обрезка строки php, функция substr(), mb_substr(),

DoubleG

Для того, чтобы заработал mb_substr() необходимо подключить в php.ini библиотеку mbstring (раскомментировать строку "extension=php_mbstring.dll" и перезапустить Apache)

А можно было сделать в одну строчку так:

echo iconv_substr($stroka, 0, 40, 'UTF-8')

Справка - http://www.php.net/manual/en/function.iconv-substr.php

Успехов

Андрей

DoubleG, спасибо за совет! Так действительно намного проще!!!

Максим

Спасибо, реально помогло. Быстро и понятно.

Андрей

Пожалуйста!! Рад стараться!!!

skywalker

mb_substr

Андрей

Skywalker, да можно использовать mb_substr,  но не у всех эта функция работает, поэтому я предложил свой вариант решения этой проблемы, и меня все устраивает, на днях переделаю этот скрипт в функцию, чтобы было еще удобней!!

арчи

работает. проверил раза4.. ураа. автор .. забегаю отныне к тебе на блог )

вот

Вот спс

DoubleG

Ты гений! Уже больше часа мучаюсь по поводу обрезки и лишнего символа в виде "вопросика в ромбике"

Андрей

Спасибо, в свое время не один часик потратил на решение этой прорблемы, а когда ничего подходящего не нашел, решил сделать по простому. Я теперь эту функцию ко всем своим сайтам подключаю, только чуть чуть доработал её.

В приведенном примере выше у функции substr_function($stroka,$chislo) только два значения, а я добавил еще третье, чтобы в обычной функции substr() можно было испоьзовать тоже третье значение.

substr_function($stroka,$chislo1,$chislo2) - substr($stroka,$chislo1,$chislo2)

 

 

Елена

СПАСИБИШЕ!!!! Автору статьи, очень выручила.))))))))))))))

Андрей

Всегда пожалуйста!

Сергей

Мне кажется так проще

$fraza = mb_substr($row2['meta_d'] ,0,40,'UTF-8')."...";

Александр

Обгромное спасибо! великолепно работает!

Антон

Спасибо большое! Помогло

Олег

Работает!!! =) Спасибо большое!!!

Alexey

Огромное спасибо, Андрей!

ПапаГот

Спс помог. У меня вообще всё показывалось вопросами.... 

Coffeeholic

Спасибо!

Виталий

слишком много ненужного кода, все проще

$text = mb_substr($text, 0, 17, "utf-8");

Дмитрий

Большое спасибо. Я получил исчерпывающий ответ на свой вопрос.

Cheshir

А если это в начале строки?

"??овар"

substr() везде заменен на mb_substr()

Андрей

Если Вы используете mb_substr(), Вам нужно:

  • либо в саму функцию подставлять кодировку каждый раз mb_substr($val, 0, 1,"utf-8");
  • либо один раз прописать такую вот строчку: mb_internal_encoding('UTF-8'); 

 

антон

помогите сделать что бы на конце небыло знака вопроса 

if( strlen( $text ) > $Doska->Config['short_echo_max_strlen'] ) $text = substr( $text, 0, $Doska->Config['short_echo_max_strlen'] )."..";

Андрей

Попробуйте так:

 

mb_internal_encoding('UTF-8');if( strlen( $text ) > $Doska->Config['short_echo_max_strlen'] ) $text = mb_substr( $text, 0, $Doska->Config['short_echo_max_strlen'] )."..";

Михаил

Просто и понятно. Спасибо!

 

billgeits86

В статье и комментариях показаны решения, но почему это происходит не объясняется. А все это из-за того, что национальные символы занимают в UTF-8 2 и более байта, а substr работает только с однобайтовыми кодировками и при обрезании строки или извлечении подстроки двухбайтовый символ может обрезаться посередине. В результате при выводе на экран кодек не сможет его правильно интерпретировать (т.к. отсутствует часть символа) и подменит на знак вопроса, обозначая тем самым невозможность конвертации. В статье вы конвертируете строку в cp1251 - однобайтовую кодировку, что в общем случае неправильно, т.к. при такой конвертации вы потеряете символы, которые есть в UTF-8, но нет в cp1251 и вместо них вы получите те же заки ? или пробел (не знаю точно как там в php). Правильнее конвертировать UTF-8 в более широкую кодировку UTF-16 или UTF-32, где символы имеют фиксированный размер, обрезать все лишнее (извлекать подстроку) и конвертировать назад. Как я понимаю iconv и mb_substr именно это и делают и лучше использовать их.

Ваши комментарии!

Имя:*


Email:*


Email:*

Не будет показан

Текст:*



Немного о нас

Да, действительно теперь я не один. В моей команде работают несколько программистов, дизайнер и отличный SMM специалист.

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

*/ ?>

Пишите!