Maintain Html With Substr()

Just wondering if Yii has any built in methods for working with substrings and maintaining the HTML, as in, say you chop a text field so yoyu only use the first 500 chars in a previews but the vut of point is mid way between an open <ul> pair of tags (For example)

If not, what ideas would people suggest for this kind of problem?

It’s not so easy to implement.

I use a function - found when searching for this topic: Cut Html





 /**

     * Truncates a string to the length of $length and replaces the last characters

     * with the ending if the text is longer than length.

     *

     * @param  $text			String		Text to truncate.

     * @param	$length			Integer		Length of returned string, including ellipsis.

     * @param	$ending			String		Ending to be appended to the trimmed string.

     * @param	$exact			Boolean		If true, $text might get cut mid-word

     * @param	$considerHtml	Boolean		If true, HTML tags would be handled correctly

     *

     * @return	String		Trimmed string.

     *

     * @see

     *    http://www.gsdesign.ro/blog/cut-html-string-without-breaking-the-tags/

     *

     */

    public static function truncate($text, $length = 100, $removetags = array(), $ending = '...', $exact = false, $considerHtml = true) {

        if (!empty($removetags)) $text = preg_replace('#<(' . implode('|', $removetags) . ')>.*?</\1>#s', '', $text);

        if ($considerHtml) {

            if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {

                return $text;

            }

            preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER);

            $total_length = strlen($ending);

            $open_tags = array();

            $truncate = '';

            foreach ($lines as $line_matchings) {

                if (!empty($line_matchings[1])) {

                    if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {

                        // do nothing

                    } else if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {

                        $pos = array_search($tag_matchings[1], $open_tags);

                        if ($pos !== false) {

                            unset($open_tags[$pos]);

                        }

                    } else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {

                        array_unshift($open_tags, strtolower($tag_matchings[1]));

                    }

                    $truncate .= $line_matchings[1];

                }

                $content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));

                if ($total_length + $content_length > $length) {

                    $left = $length - $total_length;

                    $entities_length = 0;

                    if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE)) {

                        foreach ($entities[0] as $entity) {

                            if ($entity[1]+1-$entities_length <= $left) {

                                $left--;

                                $entities_length += strlen($entity[0]);

                            } else {

                                break;

                            }

                        }

                    }

                    $truncate .= substr($line_matchings[2], 0, $left + $entities_length);

                    break;

                } else {

                    $truncate .= $line_matchings[2];

                    $total_length += $content_length;

                }

                if ($total_length>= $length) break;

            }

        } else {

            if (strlen($text) <= $length) {

                return $text;

            } else {

                $truncate = substr($text, 0, $length - strlen($ending));

            }

        }

        if (!$exact) {

            $spacepos = strrpos($truncate, ' ');

            if (isset($spacepos)) {

                $truncate = substr($truncate, 0, $spacepos);

            }

        }

        $truncate .= $ending;

        if($considerHtml) {

            foreach ($open_tags as $tag) {

                $truncate .= '</' . $tag . '>';

            }

        }

        return $truncate;

    }