Avatar billede tipsen Nybegynder
20. august 2003 - 23:59 Der er 6 kommentarer og
1 løsning

Funktion til tekst-forkortelse - kan det gøres smartere?

Hej eksperter

Jeg har bikset lidt med standardopgaven at forkorte en lang tekst og gøre den præsentabel - dvs. standardeksemplet med at forkorte en nyhedstekst til et nærmere angivet antal karakterer og tilføje ... og et link til hele nyheden.

Jeg er endt op med følgende funktion, der kan tage lidt forskellige input som kan ændre på resultatet:

/**
*
* { Funktion der afkorter tekststykker til en ønsket længde på en "pæn" måde - til brug i eksempelvis nyhedsresumeer og lignende }
*
* @param integer $desiredlength    - Ønsket længde på teksten
* @param integer $tolerance        - Tolerance på den ønskede længde dvs. teksten skal brydes indenfor $desiredlength+-tolerance
* @param mixed $delimiterchars      - De karakterer der kan brydes på i teksten. Flere karakterer angives i array.
* @param string $enddelimiters      - Hvilke tegn skal bruges som afslutter - standard er ...
*/
function CutTextNeatly($text, $desiredlength = 100, $tolerance = 10, $delimiterchars = ' ', $enddelimiters = '...') {
    if (strlen($text) > $desiredlength) {
        $text = substr($text, 0, $desiredlength+$tolerance);
        if (!is_array($delimiterchars)) {
            for ($i = 0; $i <= $tolerance; $i++) {
                if ($text[$desiredlength+$i] == $delimiterchars) {
                    $breakpos = $desiredlength + $i;
                    break;
                }
                elseif ($text[$desiredlength-$i] == $delimiterchars) {
                    $breakpos = $desiredlength - $i;
                    break;
                }
            }
        }
        else {
            for ($i = 0; $i <= $tolerance; $i++) {
                if (in_array($text[$desiredlength+$i], $delimiterchars)) {
                    $breakpos = $desiredlength + $i;
                    break;
                }
                elseif (in_array($text[$desiredlength-$i], $delimiterchars)) {
                    $breakpos = $desiredlength - $i;
                    break;
                }
            }
        }
        if (!isset($breakpos)) $breakpos = $desiredlength;
        $text = substr($text, 0, $breakpos) . $enddelimiters;
    }
    return $text;
} // end func CutTextNeatly


Jeg vil gerne høre om nogen har forslag til forbedringer eller ændringer, da det er en funktion der vil blive brugt rigtigt meget og derfor er selv en 10% hastighedsforøgelse værd at tage med :-)
Avatar billede tipsen Nybegynder
21. august 2003 - 12:47 #1
Jeg har nu selv skrevet den om, således at de karakterer der må brydes på angives i en string og ikke i et array, hvis der var flere af dem./**
* CutTextNeatly()
* { Funktion der afkorter tekststykker til en ønsket længde på en "pæn" måde - til brug i eksempelvis nyhedsresumeer og lignende }
*
* @param integer $desiredlength    - Ønsket længde på teksten
* @param integer $tolerance        - Tolerance på den ønskede længde dvs. teksten skal brydes indenfor $desiredlength+-tolerance
* @param string $delimiterchars    - De karakterer der må brydes på i teksten. Der kan angives en eller flere karakterer.
* @param string $enddelimiters      - Hvilke tegn skal bruges som afslutter - standard er "..."
*/
function CutTextNeatly($text, $desiredlength = 100, $tolerance = 10, $delimiterchars = ' ', $enddelimiters = '...') {
    if (strlen($text) > $desiredlength) {
        $text = substr($text, 0, $desiredlength+$tolerance);
        if (strlen($delimiterchars) == 1) {
            for ($i = 0; $i <= $tolerance; $i++) {
                if ($text[$desiredlength+$i] == $delimiterchars) {
                    $breakpos = $desiredlength + $i;
                    break;
                }
                elseif ($text[$desiredlength-$i] == $delimiterchars) {
                    $breakpos = $desiredlength - $i;
                    break;
                }
            }
        }
        else {
            for ($i = 0; $i <= $tolerance; $i++) {
                if (strpos($delimiterchars, $text[$desiredlength+$i]) !== false) {
                    $breakpos = $desiredlength + $i;
                    break;
                }
                elseif (strpos($delimiterchars, $text[$desiredlength-$i]) !== false) {
                    $breakpos = $desiredlength - $i;
                    break;
                }
            }
        }
        if (!isset($breakpos)) $breakpos = $desiredlength;
        $text = substr($text, 0, $breakpos) . $enddelimiters;
    }
    return $text;
} // end func CutTextNeatly
Avatar billede detox Nybegynder
22. august 2003 - 00:49 #2
Jeg mener strpos er rimelig hurtig, måske kunne du nøjes med at bruge den, selvom der kun er en 'break' karakter.
Avatar billede detox Nybegynder
22. august 2003 - 05:22 #3
Næ, jeg må bøje mig. Tjekkede det lige ud og din funktion klarer 100.000 gennemløb på ca. 2,0 sek. Hvorimod en ren strpos er ca. 2,16 sek. om det.
Avatar billede tipsen Nybegynder
22. august 2003 - 11:07 #4
OK - jeg havde ellers næsten købt den... - hvilken der "vinder" må vist afhænge lidt af længeden af det tekststykke den fodres med - men et andet problem er at styre tolerancen ordentligt sammen med strpos() - det kan jeg ikke se, hvordan det skulle grejes! (Jeg går ikke udfra du vil have den i stedet for '==', men snarere vil bruge den i stedet for gennemløbet af $text[] med for-løkken.
Avatar billede limemedia Nybegynder
23. august 2003 - 14:45 #5
ok, ved godt det er overskruet - men jeg har leget med koden, tilføjet lidt leg med evt html i strengen. Jeg har ikke benchmarked endnu og har slet ikke udført grundig test eller kodeoptimeret

here goes - med alle tænkelige forhold taget


<?php
    # html : allow, remove, display, none

    function appetizer_text($text, $length=100, $padding=10, $html='remove', $delimiter=' ', $end='...') {
        if ($html == 'allow') {
            $pos = 0;
            $count_tag = 0;
            $ignore = 0;
            $in_tag = false;
            $text_size = strlen($text);
            $out = '';

            for ($i=0; $i<$text_size; $i++){
                if ($text[$i] == '<') {
                    $in_tag = true;
                    if ($text[$i+1] == '\\') $count_tag--;
                    else $count_tag++;
                } else if ($text[$i] == '>') $in_tag = false;
               
                if (!$in_tag) $pos++;

                if ($pos > ($length-$padding)) {
                    if (($delimiter == $text[$i]) || (strpos($delimiter, $text[$i]))) $ignore = 1;
                }
               
                if (!$ignore || $in_tag || $text[$i] == '>') $out .= $text[$i];
                if ($ignore && !$count_tag) break;
            }
        } else {
            if ($html == 'remove') {
                $out = preg_replace('/<([^>]*)>/', '', $text);
            } else if ($html == 'display') {
                $out = preg_replace(array('/</', '/>/'), array('&lt;', '&gt;'), $text);
            }

            $break = $length+$padding;
            for ($i=($length+$padding); $i>($length-$padding); $i--) {
                if (($delimiter == $out[$i]) || (strpos($delimiter, $out[$i]))) $break = $i;
            }

            $out = substr($out, 0, $break);
        }

        return $out.$end;
    }
?>
Avatar billede tipsen Nybegynder
11. november 2003 - 23:28 #6
ljweb: Hvis du stadig er "i nærheden" må du da gerne lægge et svar!
Avatar billede limemedia Nybegynder
12. november 2003 - 09:06 #7
så okay da ;)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester