/** * Создание фрагмента для сниппета * * @param string $sText * @param array $aSet * @param int $nPos * @param int $nLen * * @return string */ protected function _makeSnippetFragment($sText, $aSet, $nPos, $nLen) { $nLenWord = $nLen; $nLenText = mb_strlen($sText); $nShippetOffset = floor(($this->nShippetLength - $nLenWord) / 2); // начало фрагмена if ($nPos < $nShippetOffset) { $nFragBegin = 0; } else { $nFragBegin = $nPos - $nShippetOffset; } // конец фрагмента if ($nPos + $nLenWord + $nShippetOffset > $nLenText) { $nFragEnd = $nLenText; } else { $nFragEnd = $nPos + $nLenWord + $nShippetOffset; } // Выравнивание по границе слов $sPattern = '/' . $this->sPatternW . '+$/uisxSXU'; if ($nFragBegin > 0 && mb_preg_match($sPattern, mb_substr($sText, 0, $nFragBegin), $m, PREG_OFFSET_CAPTURE)) { $nFragBegin -= mb_strlen($m[0][0]); } $sPattern = '/^' . $this->sPatternW . '+/uisxSXU'; if ($nFragEnd < $nLenText && mb_preg_match($sPattern, mb_substr($sText, $nFragEnd), $m, PREG_OFFSET_CAPTURE)) { $nFragEnd += mb_strlen($m[0][0]) + $m[0][1]; } // Обрезание по максимальной длине if ($this->nShippetMaxLength > 0 && ($nOver = $nFragEnd - $nFragBegin - $this->nShippetMaxLength) > 0) { $nFragBegin -= floor($nOver / 2); if ($nFragBegin < 0) { $nFragBegin = 0; } if ($nFragBegin > $nPos) { $nFragBegin = $nPos; } $nFragEnd = $nFragBegin + $this->nShippetMaxLength; if ($nFragEnd < $nPos + $nLenWord) { $nFragEnd = $nPos + $nLenWord; } } $sFragment = ''; // * Укладываем слова из одного сета в один фрагмент $iBegin = $nFragBegin; foreach ($aSet as $aWord) { $iWordPos = $aWord['pos']; $sFragment .= str_replace('>', '>', str_replace('<', '<', mb_substr($sText, $iBegin, $iWordPos - $iBegin))); $sFragment .= $this->sSnippetBeforeMatch . $aWord['txt'] . $this->sSnippetAfterMatch; $iBegin = $iWordPos + $aWord['len']; } $sFragment .= str_replace('>', '>', str_replace('<', '<', mb_substr($sText, $iBegin, $nFragEnd - $iBegin))); $sFragment = ($nFragBegin > 0 ? '…' : '') . $sFragment . ($nFragEnd < $nLenText ? '…' : ''); $sFragment = str_replace('<br/>', '', $sFragment); return $sFragment; }
/** ************************************************************************************************************ * Function to truncate and shorten text * * @param string $html The html code which should be shortened * @param int $length The length to which the text should be shortened * @param bool skip If this value is true the truncate will be skipped (nothing will be done) * @param bool perserve_tags Specifies if html tags should be preserved or if only the text should be shortened ***************************************************************************************************************/ public function truncate($html, $length, $skip = false, $preserve_tags = true) { mb_internal_encoding("UTF-8"); if (0 >= $length || mb_strlen($html) <= $length || $skip) { // do nothing return $html; } elseif (!$preserve_tags) { // only shorten text return mb_substr($html, 0, $length); } else { // truncate with preserving html tags $printedLength = 0; $position = 0; $tags = array(); $out = ''; while ($printedLength < $length && mb_preg_match('{</?([a-z]+\\d?)[^>]*>|&#?[a-zA-Z0-9]+;}', $html, $match, PREG_OFFSET_CAPTURE, $position)) { list($tag, $tagPosition) = $match[0]; // Print text leading up to the tag $str = mb_substr($html, $position, $tagPosition - $position); if ($printedLength + mb_strlen($str) > $length) { $out .= mb_substr($str, 0, $length - $printedLength); $printedLength = $length; break; } $out .= $str; $printedLength += mb_strlen($str); if ('&' == $tag[0]) { // Handle the entity $out .= $tag; $printedLength++; } else { // Handle the tag $tagName = $match[1][0]; if ('/' == $tag[1]) { // This is a closing tag $openingTag = array_pop($tags); assert($openingTag == $tagName); // check that tags are properly nested $out .= $tag; } else { if ('/' == $tag[mb_strlen($tag) - 2]) { // Self-closing tag $out .= $tag; } else { // Opening tag $out .= $tag; $tags[] = $tagName; } } } // Continue after the tag $position = $tagPosition + mb_strlen($tag); } // Print any remaining text if ($printedLength < $length && $position < mb_strlen($html)) { $out .= mb_substr($html, $position, $length - $printedLength); } // Print ellipsis ("...") if the html is not complete if (mb_strlen($html) != $position) { $out .= ' …'; } // Close any open tags. while (!empty($tags)) { $out .= '</' . array_pop($tags) . '>'; } return $out; } }
/** ************************************************************************************************** * Truncate HTML, close opened tags * * @param int $max_length The length (number of characters) to which the text will be * shortened. With "0" the full text will be returned. With "auto" * also the complete text will be used, but a wrapper div will be * added which shortens the text to 1 full line via css. * @param string $html The html code which should be shortened. * @param string $wrapper_type Defines which kind of wrapper shall be added around the html code * if a manual length shall be used. The possible values are "none", * "div" and "span". With "none" no wrapper will be added, "div" and * "span" are the 2 available wrapper types. * If max_length is set to auto a div is mandatory and will be added * always, independent of the given value. * @param array $wrapper_attributes Additional attributes for the wrapper element. The array * key defines the attribute name. *****************************************************************************************************/ private function truncate($max_length, $html, $wrapper_type = 'none', $wrapper_attributes = array()) { // Apply wrapper and add required css for autolength (if required) $autolength = 'auto' == $max_length ? true : false; if ($autolength) { $wrapper_type = 'div'; } elseif ('div' != $wrapper_type && 'span' != $wrapper_type) { $wrapper_type = 'none'; } if ('none' != $wrapper_type) { $wrapper_text = '<' . $wrapper_type; foreach ($wrapper_attributes as $name => $value) { $wrapper_text .= ' ' . $name . '="' . $value . '"'; } if ($autolength) { $wrapper_text .= ' style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis"'; } $html = $wrapper_text . '>' . $html . '</' . $wrapper_type . '>'; } // Apply manual length mb_internal_encoding("UTF-8"); if (is_numeric($max_length) && 0 < $max_length && mb_strlen($html) > $max_length) { $printedLength = 0; $position = 0; $tags = array(); $out = ''; while ($printedLength < $max_length && mb_preg_match('{</?([a-z]+\\d?)[^>]*>|&#?[a-zA-Z0-9]+;}', $html, $match, PREG_OFFSET_CAPTURE, $position)) { list($tag, $tagPosition) = $match[0]; // Print text leading up to the tag $str = mb_substr($html, $position, $tagPosition - $position); if ($printedLength + mb_strlen($str) > $max_length) { $out .= mb_substr($str, 0, $max_length - $printedLength); $printedLength = $max_length; break; } $out .= $str; $printedLength += mb_strlen($str); if ('&' == $tag[0]) { // Handle the entity $out .= $tag; $printedLength++; } else { // Handle the tag $tagName = $match[1][0]; if ('/' == $tag[1]) { // This is a closing tag $openingTag = array_pop($tags); assert($openingTag == $tagName); // check that tags are properly nested $out .= $tag; } else { if ('/' == $tag[mb_strlen($tag) - 2]) { // Self-closing tag $out .= $tag; } else { // Opening tag $out .= $tag; $tags[] = $tagName; } } } // Continue after the tag $position = $tagPosition + mb_strlen($tag); } // Print any remaining text if ($printedLength < $max_length && $position < mb_strlen($html)) { $out .= mb_substr($html, $position, $max_length - $printedLength); } // Print ellipsis ("...") if the html is not complete if (mb_strlen($html) != $position) { $out .= ' …'; } // Close any open tags. while (!empty($tags)) { $out .= '</' . array_pop($tags) . '>'; } return $out; } return $html; }
/** * Создание фрагмента для сниппета */ protected function MakeSnippetFragment($text, $set, $pos, $len) { $fragment = ''; $lenWord = $len; $lenText = mb_strlen($text); $this->nShippetOffset = floor(($this->nShippetLength - $lenWord) / 2); // начало фрагмена if ($pos < $this->nShippetOffset) { $fragBegin = 0; } else { $fragBegin = $pos - $this->nShippetOffset; } // конец фрагмента if ($pos + $lenWord + $this->nShippetOffset > $lenText) { $fragEnd = $lenText; } else { $fragEnd = $pos + $lenWord + $this->nShippetOffset; } // Выравнивание по границе слов if ($fragBegin > 0 && mb_preg_match('/' . $this->sPatternW . '+$/uisxSX', mb_substr($text, 0, $fragBegin), $m)) { $fragBegin -= mb_strlen($m[0][0]); } if ($fragEnd < $lenText && mb_preg_match('/' . $this->sPatternW . '+/uisxSX', mb_substr($text, $fragEnd), $m)) { $fragEnd += mb_strlen($m[0][0]) + $m[0][1]; } // Обрезание по максимальной длине if ($this->nShippetMaxLength > 0 && ($nOver = $fragEnd - $fragBegin - $this->nShippetMaxLength) > 0) { $fragBegin -= floor($nOver / 2); if ($fragBegin > $pos) { $fragBegin = $pos; } $fragEnd = $fragBegin + $this->nShippetMaxLength; if ($fragEnd < $pos + $lenWord) { $fragEnd = $pos + $lenWord; } } $fragment = ''; // * Укладываем слова из одного сета в один фрагмент $begin = $fragBegin; foreach ($set as $word) { $pos = $word['pos']; $fragment .= str_replace('>', '>', str_replace('<', '<', mb_substr($text, $begin, $pos - $begin))); $fragment .= $this->sSnippetBeforeMatch . $word['txt'] . $this->sSnippetAfterMatch; $begin = $pos + $word['len']; } $fragment .= str_replace('>', '>', str_replace('<', '<', mb_substr($text, $begin, $fragEnd - $begin))); $fragment = ($fragBegin > 0 ? '…' : '') . $fragment . ($fragEnd < $lenText ? '…' : ''); $fragment = str_replace('<br/>', '', $fragment); return $fragment; }