[ Ilidan13 @ 17.10.2009. 09:35 ] @
Pozdrav!
Na sajtu imam napravljeno dodavanje novosti preko Yahoo Rich Text Box-a. On formatira tekst novosti dodavanje html tagova, tako da u bazi pod tekstom novosti imam i dodane odgovarajuće html tagove, tipa <br>, <b> <p>.
E sad, ja želim korisniku prikazati listu novosti na taj način da mu prikažem naslov novosti, i ispod njega odgovarajuću skraćenu verziju teksta novosti (npr. prvih 50 znakova novosti, ili prvih 15 riječi). Tada korisnik može kliknuti na naslov i otvoriti čitavu novost.
Međutim kod prikaza skraćene verzije mi ponekad poremeti čitavu strukturu web stranice, pretpostavljam zbog toga što dohvati dio teksta novosti i samo dio tagova unutar njega, pa ostane poneki ne zatvoreni tag. Zanima me na koji način se to može riješiti?
Hvala!
[ Nemanja Avramović @ 17.10.2009. 09:55 ] @
Ja koristim kombinaciju ove dve f-je.

Code:
function close_tags ( $html )
{
    preg_match_all ( "#<([a-z]+)( .*)?(?!/)>#iU", $html, $result );
    $openedtags = $result[1];

    preg_match_all ( "#</([a-z]+)>#iU", $html, $result );
    $closedtags = $result[1];
    $len_opened = count ( $openedtags );
    if( count ( $closedtags ) == $len_opened )
    {
        return $html;
    }
    $openedtags = array_reverse ( $openedtags );
    for( $i = 0; $i < $len_opened; $i++ )
    {
        if ( !in_array ( $openedtags[$i], $closedtags ) )
        {
            $html .= "</" . $openedtags[$i] . ">";
        }
        else
        {
            unset ( $closedtags[array_search ( $openedtags[$i], $closedtags)] );
        }
    }
    return $html;
}

function elliStr($s,$n) {
    for ( $x = 0; $x < strlen($s); $x++ ) {
        $o = ($n+$x >= strlen($s) ? $s : ($s{$n+$x} == " " ? substr($s,0,$n+$x) . "..." : ""));
        if ( $o != "" ) { return $o; }
    }
}


Moguće je da može i ovako doći do problema, ali teže nego kad ručno to radiš

A ove dve f-je kombinuješ ovako:

Code:
echo close_tags(elliStr($dugacak_text, $duzina));


To će odseći $dugacak_text posle $duzina karaktera, s tim što neće preseći reč na pola već će naći kraj reči i tu će iseći string. Zatim f-ja close_tags() prolazi kroz taj odlomak teksta, nalazi otvorene (a nezatvorene) tagove i zatvara ih.
[ Miroslav Ćurčić @ 17.10.2009. 16:30 ] @
Sa strip_tags() ukloniš sve tagove iz teksta i to prikažeš.

Pre toga bi trebalo da odradiš $txt= str_replace( '</', ' </', $txt ); što će dodati razmake na spojevima tagova što će tekst učiniti čitkijim.
[ Aleksandar Ružičić @ 17.10.2009. 17:49 ] @
evo moje funkcije za to:
Code:

define('XHTML_CHOP_WORDS',            0x00);
define('XHTML_CHOP_CHARS',            0x01);
define('XHTML_CHOP_NO_WORD_BREAK',    0x10);
define('XHTML_CHOP_ELIPSIS_OUT',    0x20);
define('XHTML_CHOP_NO_EMPTY_TAGS',    0x40);
define('XHTML_CHOP_LETTERS',        XHTML_CHOP_CHARS | XHTML_CHOP_NO_WORD_BREAK);

function xhtml_chop($html, $max, $mode = XHTML_CHOP_WORDS, $elipsis = '...') {

    $stack = array();
    $ret = '';
    $total = 0;
    $done = false;

    $nonempty = create_function('$word', 'return !empty($word);');

    $html = preg_replace('/\s+/', ' ', $html);

    while ($html and !$done) {

        if (!preg_match('|<(/?\w+)[^>]*/?>|', $html, $matches, PREG_OFFSET_CAPTURE)) {

            $text = $html;
            $tag = false;

        } else {

            $tag = $matches[0][0];
            $tag_start = $matches[0][1];
            $text = substr($html, 0, $tag_start);
        }

        if ($text) {

            if ($text[0] == ' ') {
                $ret .= ' ';
            }

            if ($mode & XHTML_CHOP_CHARS) {

                $num_chars = strlen($text = trim($text, ' '));

                if ($total + $num_chars > $max) {

                    $done = true;

                    if ($mode & XHTML_CHOP_NO_WORD_BREAK) {

                        $num_chars = $max - $total;
                        $text = substr($text, 0, $num_chars) . preg_replace('/\s.*$/', '', substr($text, $num_chars));

                    } else {
                        $text = rtrim(substr($text, 0, $max - $total));
                    }
                }

                $total += $num_chars;

            } else { // XHTML_CHOP_WORDS

                if (($num_words = count($words = array_filter(explode(' ', $text), $nonempty))) > 0) {

                    if ($total + $num_words > $max) {
                        $done = true;
                        $words = array_slice($words, 0, $max - $total);
                    }

                    $total += $num_words;
                    $text = implode(' ', $words);
                }
            }

            $ret .= $text;
        }

        if (!$tag) {
            break;
        }

        if ($matches[1][0][0] != '/') {
            $stack[] = $matches[1][0];
        } else {

            if (empty($stack) and !$done) {
                $html = substr($html, $tag_start + strlen($tag));
                continue;
            }

            while ($close_tag = array_pop($stack)) {
                if (strtolower($close_tag) == strtolower(substr($matches[1][0], 1))) {
                    break;
                } else {
                    $ret .= "</$close_tag>";
                }
            }
        }

        if ($tag_start and $html[$tag_start - 1] == ' ') {
            $ret .= ' ';
        }

        $ret.= $tag;
        $html = substr($html, $tag_start + strlen($tag));
    }

    if ($mode & XHTML_CHOP_NO_EMPTY_TAGS and substr(rtrim($ret, ' '), -1) == '>') {
        array_pop($stack);
        $ret = substr($ret, 0, strrpos($ret, '<'));
    }

    if ($done and ~$mode & XHTML_CHOP_ELIPSIS_OUT) {
        $ret .= $elipsis;
    }

    if (!empty($stack)) {

        $self_closing = array('img', 'input', 'br', 'hr', 'link', 'base', 'meta');

        while ($tag = array_pop($stack)) {
            if (!in_array(strtolower($tag), $self_closing)) {
                $ret .= "</$tag>";
            }
        }
    }

    if ($done and $mode & XHTML_CHOP_ELIPSIS_OUT) {
        $ret .= $elipsis;
    }

    return $ret;
}

"duza" je od Nemanjine, ali zato pri brojanju uzima samo text u obzir, ne i markup. takodje je moguce birati izmedju broja reci (sto je preferiram) ili broja karaktera (sa opcijom da se ne dozvoli secenje reci)...

ja je koristim vec dugo (napisao sam je upravo iz istog razloga: trebala mi je fja koja ce neki html iseci na odredjeni broj reci s tim da se markup zadrzi koliko god je moguce) i nisam nailazio na probleme sa njom. ako joj se prosledi validan xhtml, validan ce i vratiti...
[ Ilidan13 @ 18.10.2009. 12:44 ] @
Super. Zahvaljujem svima na odgovoru. Ostaje mi samo još da malo proučim ove funkcije i odlučim koja mi najbolje odgovara.
Hvala još jednom.