Обрезать HTML-текст с учетом "полной остановки" (в CachePHP TextHelper-> truncate) - PullRequest
4 голосов
/ 16 сентября 2011

Редактировать:

В итоге я использовал CakePHP truncate().Это намного быстрее и поддерживает Unicode: D

Но вопрос все еще остается:

Как сделать так, чтобы функция автоматически определяла точки полного останова (.) и сразу после этого отключала ее?Так что в основном $length будет почти игнорироваться.Таким образом, если в новом тексте будет неполное предложение, будет добавлено больше слов, пока предложение не закончится (или удаляется, в зависимости от длины строки от обрезки до следующего / предыдущего предложения)

Правка 2: Я узнал, как определять полные остановки.Я заменил:

 if (!$exact) {
   $spacepos = mb_strrpos($truncate, ' ');

 ...

на

 if (!$exact) {
    $spacepos = mb_strrpos($truncate, '.');
 ...

edit - проблема:

Когда у меня есть теги типа img, которые имеют точки внутриих атрибуты, текст обрезается внутри тега:

 $text = '<p>Abc def abc def abc def abc def. Abc def <img src="test.jpg" /></p><p>abc def abc def abc def abc def.</p>';

 echo htmlentities(truncate($text));

Как я могу это исправить?Я открою щедрость, потому что на первоначальный вопрос уже был дан ответ ...

Ответы [ 3 ]

5 голосов
/ 16 сентября 2011

Этот фрагмент решает, что вы ищете, и перечисляет его неудачи (полные остановки могут не указывать на конец предложения, а другие знаки препинания могут заканчивать предложения).

Он будет сканировать символыдо $maxLen, а затем эффективно «выбрасывать» частичное предложение после последней найденной им полной остановки.

В вашем случае вы бы использовали эту функцию непосредственно перед возвратом $new_text.

2 голосов
/ 21 сентября 2011

Чтобы решить проблему «полной остановки в теге», вы можете использовать нечто похожее на следующее, чтобы определить, находится ли остановка в теге:

$str_len       = strlen($summary);
$pos_stop      = strrpos($summary, '.');
$pos_tag_open  = strrpos($summary, '<', -($str_len - $pos_stop));
$pos_tag_close = strpos($summary, '>', $pos_tag_open);

if (($pos_tag_open < $pos_stop) && ($pos_stop < $pos_tag_close)) {
  // Inside tag! Search for the next nearest prior full-stop.
  $pos_stop = strrpos($summary, '.', -($str_len - $pos_tag_open));
}

echo htmlentities(substr($summary, 0, $pos_stop + 1));

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

Edit:

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

$text = '<p>Abc def abc def abc def abc def. Abc def <img src="test.jpg" />abc</p>';

$count = preg_match_all("/\.(?!([^<]+)?>)/", $text, $arr, PREG_OFFSET_CAPTURE);
$offset = $arr[0][$count-1][1];

echo substr($text, 0, $offset + 1)."\n";

Это должно быть относительно эффективно, по крайней мере, по сравнению с truncate(), который также использует preg_match для внутреннего использования.

1 голос
/ 25 сентября 2011

Регулярное выражение выше Усечение HTML-текста с учетом "полной остановки" (в CachePHP TextHelper-> truncate) может работать.

Но, учитывая эффективность, в этом случае мы могли бы сначала обрезать строку до max_length , а затем выполнить preg для усеченной строки.И да, необходимо учитывать символы пунктуации.

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

  1. пробел или EOL послесимвол пунктуации
  2. Первое слово после выбранной пунктуации с верхним регистром.
  3. Несколько новых строк (конец абзаца) после символа пунктуации и т. д.
...