[php] Skracanie tekstu z uwzględnieniem bbcode

0

Chcę, żeby na stronie głównej były wyświetlane tylko początki newsów - pierwsze 600 znaków. Problem polega na tym, że w newsach mogą być stsowane tagi bbcode:
[img][/img], [quote][/quote], [url][/url], [url=],[/url], [b][/b], [i][/i], [u][/u], [color=][/color], [br], [hr], [center][/center]
I jeśli cały tag nie zmieści się w tych 600 znakach (zacznie się, ale nie skończy), to będą komplikacje. Chyba wiadomo jakie.
Czy wie ktoś w jaki sposób się przed tym zabezpieczyć? Chciałbym, żeby było coś takiego, że jeśli nie zmieści się tag np. obrazka, to zostanie pominięty całkiem(wycięty), czyli tekst zostanie skrócony do miejsca gdzie zaczyna się ten tag. Jeśli się zmieści, to oczywiście ma zostać. Jeśli nie zmieszczą się całe tagi takie jak [b], [u], [quote] itp, to zostaną po prostu zamknięte wcześniej, zaraz po tych 600 znakach.
Wie ktoś jak takie coś zrobić?

1

Nie prościej wyciąć wszystkie tagi (bez ich zawartosci oczywiscie), i dopiero później obcinac do 600 znaków?

0

No, ale pasuje, żeby na stronie głównej te taki też działały, a jak je wytnę, to chyba nic z tego

0

Generalnie w inny sposób, poza ręcznym liczeniem znaków i patrzeniem, czy rozpoczęty tag został zamknięty, nic nie zrobisz.
Czyli liczysz znaczki, każde wystąpienie '[' sprawdzasz, czy jest rozpoczęciem taga, jeśli tak to przestajesz liczenia aż do ']', sprawdzasz czy tag jest pojedynczy czy podwójny, jeśli podwójny to odkładasz go sobie na stos. Liczysz dalej, aż natkniesz się na zakończenie taga (jeśli był podwójny), zdejmujesz go wtedy za stosu, i kiczysz dalej. Jak dojdziesz do 600, to sprawdzasz czy na stosie są jeszcze jakieś tagi, jak tak, to je zamykasz i wtedy kończysz.

Oczywiście nie znaczy że masz o robić po jednej literce - pokombinuj albo z regexpami (choć nie wiem czy sensownie Ci tutaj pomogą), albo strpos(), albo różne takie. Walcz :)

Ale zagadnienie nawet ciekawe, może jak znajde chwilę wolnego to napiszę jakieś przyjemne narzędzie do tego :) Zapisuję sobie pomysł w moim małym TODO ;)

0

ucinasz 600 znaków, szukasz ostatniej pozycji [ i osobno ], jeśli pozycja [ jest późniejsza niż ostatniego ] to dodajesz na końcu ] albo ucinasz wszystko po nim i parsujesz normalnie jak to robisz przy pełnym artykule (oczywiście zadziała jeśli obsługę tego bbcode'u masz poprawnie zrobioną)

0

@Adamo: ale wtedy cała zajawka nie będzie widoczna jako 600 znaków, tylko 600 znaków - długość znaczników. Czyli w skrajnych wypadkach może jej prawie nie być.
A sądzę że da się to zrobić całkiem efektywnie w taki sposób jak opisałem.

0

aha fuckt, jakoś późno było to coś mi się poprzestawiało ;P
@nav: to chyba raczej do tego wątku
//tru - n

no na pewno nie da się tego zrobić inaczej niż mysz sugeruje, jedyne pytanie czy trzeba się bawić po znaku czy też strpos i tym podobne czy można wykorzystać gotowe funkcje

0

Najlepsza koncpecja, jaką udało mi się wymyśleć tak na dość szybko, to to co poniżej:

//funkcja pomocnicza
//zwraca:
//nazwa tagu - jeśli jest to rozpoczęcie tagu podwojnego
//1 - jeśli to pojedynczy tag
//0 - jeśli to zwykły tekst
//-1 - jeśli to zakończenie tagu
function check_tag($s) {
        if (preg_match('!^\[(img|quote|url|b|i|u|color|center)(\s*=\s*.*?)?\]$!i', $s, $match)) { //tag rozpoczynający
                return $match[1];
        } else if (preg_match('!^\[/(img|quote|url|b|i|u|color|center)\]$!i', $s)) { //tag kończący
                return -1;
        } else if (preg_match('!^\[(br|hr)\]$!i', $s)) { //tag pojedynczy
                return 1;
        } else { // zwykly string
                return 0;
        }
}

//$str    - string
//$len    - długość
//$type   - string lub array
//$concat - string służący do łączenia poszczególnych kawałków
function strTagsCut($str, $len, $type='string', $concat='') {
        static $tags = array(
                'single' => array('br', 'hr'),
                'double' => array('img','quote','url','b', 'i', 'u', 'color', 'center'),
        );
        $pat = sprintf('!(\[/?(?:%s|%s)(?:\s*=\s*.*?]*)?\])!i',
                implode('|', $tags['single']),
                implode('|', $tags['double'])
        );

        $splitted = preg_split($pat, $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
        $count    = 0;
        $stack    = array();
        $new      = array();
        foreach ($splitted as $part) {

                $tag = check_tag($part);
                if (is_string($tag)) {
                        array_push($stack, $tag);

                } else if ($tag === 0) {
                        $l = strlen($part);
                        if (($count+$l) >= $len) {
                                $new[] = substr($part, 0, -($count+$l-$len));
                                foreach (array_reverse($stack) as $el) {
                                        $new[] = sprintf('[/%s]', $el);
                                }
                                break;
                        }
                        $count += $l;

                } else if ($tag === -1) {
                        array_pop($stack);
                }

                $new[] = $part;

        }

        return $type=='array' ? $new : join($concat, $new);
}

Sposób użycia:

echo strTagsCut($jakis_tekst, 600);
0

Dzięki za kod. W sumie, to nie liczyłem, że komuś się będzie chciało całą funkcję pisać, tylko ktoś mi coś podpowie, więc naprawdę dzięki za pomoc.
Tylko dalej jest pewnien problem z tagami:
[url]http://asdasdasdasdasd[/url] i [img]http://cośtamasdasdasdasd[/img]

[url=http:/asdasdasdasdasd]nazwa linka[/url] działa dobrze, bo skraca najwyżej tekst nazwa linka, ale [url]http://www.asdasdasd.asd[/url] nie może skracać tekstu wewnątrz tagów, bo właśnie tam jest url. Da się coś z tym zrobić? Tak samo z img, bo wtedy otrzymam niepełny adres obrazka

0

A może na serwer też wgrać za Ciebie? :/ IMO to już trochę się wysilić możesz sam. I tak zrobiłem dużo. Jak widzę, za dużo...

Manual trackback: http://urzenia.net/316/skracanie-tekstu/

0

Złotą łopatę za odkopanie wątku dla mnie poproszę :) Akurat szukam jak tu dobrze pociąć tekst a tu taki banał :) Warto czasem sobie przypomnieć że w php nie to co się zna pamięciowo ale to jak się umie wykorzystać podstawy. Dzięki.

0

Zamiast ilosci znakow lepiej ograniczyc ilosc wyrazow. Wtedy znika problem ze "zmieszczeniem sie" w ilosci znakow.

1 użytkowników online, w tym zalogowanych: 0, gości: 1