Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Корректная обрезка строк
Форумы портала PHP.SU » » Хранение данных, их вывод и обработка » Корректная обрезка строк

Страниц (1): [1]
 

1. StormMan - 10 Июня, 2010 - 18:49:10 - перейти к сообщению
Всем привет!
Есть такой модуль обрезки строки, это плагин для Smarty, но используются обычные функции:

PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. function smarty_modifier_truncate($string, $length = 80, $etc = '...',
  3.                                   $break_words = false, $middle = false)
  4. {
  5.     if ($length == 0)
  6.         return '';
  7.  
  8.     if (strlen($string) > $length) {
  9.         $length -= strlen($etc);
  10.         if (!$break_words && !$middle) {
  11.             $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1));
  12.         }
  13.         if(!$middle) {
  14.             return substr($string, 0, $length).$etc;
  15.         } else {
  16.             return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
  17.         }
  18.     } else {
  19.         return $string;
  20.     }
  21. }
  22. ?>


Проблема этого кода в том, что он неправильно работает с кодировкой utf-8, если символы отличаются от латиницы, и исходит эта проблема из-за того, что с многобайтными символами функция substr работать не умеет. Заменяю её на mb_substr:

PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. function smarty_modifier_truncate($string, $length = 80, $etc = '...',
  3.                                   $break_words = false, $middle = false)
  4. {
  5.     if ($length == 0)
  6.         return '';
  7.  
  8.     if (mb_strlen($string, utf8) > $length) {
  9.     //if (strlen($string) > $length) {
  10.         $length -= mb_strlen($etc, utf8);
  11.         //$length -= strlen($etc);
  12.         if (!$break_words && !$middle) {
  13.             $string = mb_ereg_replace('/\s+?(\S+)?$/', '', mb_substr($string, 0, $length+1, utf8), utf8);
  14.             //$string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1));
  15.         }
  16.         if(!$middle) {
  17.             return mb_substr($string, 0, $length, utf8).$etc;
  18.             //return substr($string, 0, $length).$etc;
  19.         } else {
  20.             return mb_substr($string, 0, $length/2, utf8) . $etc . mb_substr($string, -$length/2, utf8);
  21.             //return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
  22.         }
  23.     } else {
  24.         return $string;
  25.     }
  26. }
  27. ?>


Остаётся одна проблема: слова обрезаются посередине, получается ерунда вроде "Слова обрезаются посе...". Подскажите, какие функции можно применить, чтобы текст обрезался правильно: "Слова обрезаются посередине...".

Буду очень благодарен за примеры!
2. JustUserR - 11 Июня, 2010 - 15:10:42 - перейти к сообщению
StormMan пишет:
Остаётся одна проблема: слова обрезаются посередине, получается ерунда вроде "Слова обрезаются посе...". Подскажите, какие функции можно применить, чтобы текст обрезался правильно: "Слова обрезаются посередине...".
Для того чтобы не обрезать слова по середине нужно определиться с символов который является границей слова это может быть пробел и знаки пунктуации - соответственно вы можете получить индекс $v последнего символа в вашей функции но саму строку не обрезать - а запустить цикл который будет по очереди проверять символы и если они не являются символами границы слова то прибавлять значение $v на единицу Соответственно когда цикл завершится то вы получите значение $v по которому можно обрезать подстроку
Похожую задачу можно решить и в регулярном выражении за счет функции просмотра вперед
3. ZeiZ - 11 Июня, 2010 - 16:07:54 - перейти к сообщению
PHP:
скопировать код в буфер обмена
  1.  
  2. $words = 20; // Количество слов которые надо вывести
  3. $text = explode(" ", $text);
  4. for ($i=0;$i<$words;$i++) $fraza = $fraza.$text[$i]." ";
  5. $fraza = $fraza."...";
  6.  
  7. echo($fraza);
  8.  


Это сходу, не проверял, но должно работать.
4. JustUserR - 11 Июня, 2010 - 16:15:05 - перейти к сообщению
ZeiZ пишет:
Это сходу, не проверял, но должно работать
Работать должно но для больших текстов это достаточно медленное и ресурсоемкое решение - ведь потребуется в два раза болье памяти поскольку будет создан массив со словами текста а также разбивка осуществляется достаточно медленно Именно поэтому лучше делать разбивку индуктивно - то есть сразу получить небольшую часть текста в заданных пределах и уже внутри нее выполнять определенные операции
5. ZeiZ - 11 Июня, 2010 - 16:22:13 - перейти к сообщению
JustUserR разумеется речь идёт о небольших текстах.
6. JustUserR - 11 Июня, 2010 - 16:57:38 - перейти к сообщению
ZeiZ пишет:
JustUserR разумеется речь идёт о небольших текстах.
В таком случае использование похожего алгортма весьма возможно только нужно учитываь не количетсво слов а количество символов - поэтому можно создать переменную в которой будет храниться результурующее значение и в цикле можно конкатериовать в нее по слову пока значение не превысит заданной длины
Также хорошо делать проверку на тот случай если входящий текст вообще не будет содержать пробелов (Если текст берется автоматически из какого-то источника) - и в таком случае нужно ввести принудительную длину по которой он будет образеться
7. ZeiZ - 11 Июня, 2010 - 17:13:50 - перейти к сообщению
JustUserR спасибо, поправлю свой код, проверю скорость, отпишу.
8. JustUserR - 13 Июня, 2010 - 12:46:03 - перейти к сообщению
ZeiZ пишет:
JustUserR спасибо, поправлю свой код, проверю скорость, отпишу.
Пожалуйста! Могу вам привести тот PHP-код на основе вашего - который лишен вышеукзаанного недостатка и некоторых семантических ошибок
PHP:
скопировать код в буфер обмена
  1. $symbs = 20; // Количество симловов которые надо вывести
  2. $fraza="";
  3. $words = explode(" ", $text);
  4. for($i=0;$i<count($words);$i++)
  5. {$nv_str=$fraza.$words[$i]." ";
  6. if(strlen($nv_str)<$symbs)
  7. {$fraza= $nv_str;}
  8. else {break;}
  9. }
  10. $fraza = $fraza."...";
  11. echo($fraza);
Если улучшать данную задачу далее то можно было бы проводить дополнительный синтаксический анализ текста - чтобы оно к примеру заканчивалось завершенным предложением или его частью - но это уже достаточно сложный грамматический анализ
9. dahelp - 08 Сентября, 2011 - 09:02:45 - перейти к сообщению
JustUserR пишет:
Пожалуйста! Могу вам привести тот PHP-код на основе вашего - который лишен вышеукзаанного недостатка и некоторых семантических ошибок


"..." ставит! если текст меньше $symbs. Как дописать функцию, чтобы если $text < $symbs не дописывал "..."?
10. EuGen - 08 Сентября, 2011 - 09:06:40 - перейти к сообщению
Пожалуйста, в новую тему - эта устарела

 

Powered by ExBB FM 1.0 RC1