Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cutting text without destroying html tags

Is there a way to do this without writing my own function?

For example:

$text = 'Test <span><a>something</a> something else</span>.';
$text = cutText($text, 2, null, 20, true);
//result: Test <span><a>something</a></span>

I need to make this function indestructible

My problem is similar to This thread but I need a better solution. I would like to keep nested tags untouched.

So far my algorithm is:

function cutText($content, $max_words, $max_chars, $max_word_len, $html = false) {
    $len = strlen($content);
    $res = '';

    $word_count = 0;
    $word_started = false;
    $current_word = '';
    $current_word_len = 0;

    if ($max_chars == null) {
        $max_chars = $len;
    }
    $inHtml = false;
    $openedTags = array();
    for ($i = 0; $i<$max_chars;$i++) {

        if ($content[$i] == '<' && $html) {
            $inHtml = true;
        }

        if ($inHtml) {
            $max_chars++;
        }       

        if ($html && !$inHtml) {

            if ($content[$i] != ' ' && !$word_started) {
                $word_started = true;
                $word_count++;
            }

            $current_word .= $content[$i];
            $current_word_len++;

            if ($current_word_len == $max_word_len) {
                $current_word .= '- ';
            }

            if (($content[$i] == ' ') && $word_started) {
                $word_started = false;
                $res .= $current_word;
                $current_word = '';
                $current_word_len = 0;
                if ($word_count == $max_words) {
                    return $res;
                }
            }
        }

        if ($content[$i] == '<' && $html) {
            $inHtml = true;
        }
    }
    return $res;
}

But of course it won't work. I thought about remembering opened tags and closing them if they were not closed but maybe there is a better way?

like image 767
Kaminari Avatar asked Apr 09 '11 00:04

Kaminari


1 Answers

This works perfectly for me:

function trimContent ($str, $trimAtIndex) {

    $beginTags = array();       
    $endTags = array();

    for($i = 0; $i < strlen($str); $i++) {
        if( $str[$i] == '<' )
            $beginTags[] = $i;
        else if($str[$i] == '>')
           $endTags[] = $i;
    }

    foreach($beginTags as $k=>$index) {
        // Trying to trim in between tags. Trim after the last tag
        if( ( $trimAtIndex >= $index ) && ($trimAtIndex <= $endTags[$k])  ) {
            $trimAtIndex = $endTags[$k];
        }
    }

    return substr($str, 0, $trimAtIndex);
}
like image 170
Helen Vasconcelos Avatar answered Oct 03 '22 09:10

Helen Vasconcelos