HTML-Code kürzen
Diese Funktion schneidet HTML-Code nach n Zeichen ab. Dabei werden Entities als jeweils 1 Zeichen berechnet und nicht zerschnitten, ebenso zählen HTML-Tags nicht zur Länge und werden ebenfalls nicht zerstört. Auf Wunsch kann die Klasse nach dem Abschneiden die nun offenen Tags auch wieder schließen.
<?php
function shortenText($text, $length, $closeTags = false) {
$text = trim($text);
if ( strlen($text) <= $length ) return $text;
// HTML-Tags extrahieren, speichern und im Text
// durch Extra-Markierungen ersetzen
$htmlTagMap = array();
$counter = 0;
$shortened = 0; // Die Länge, die schon rausgestrichen wurde, wird in jedem Durchlauf größer
preg_match_all("#<((/?[a-z]+)[^>]*)>#s",$text,$matches, PREG_OFFSET_CAPTURE);
if ( $matches ) {
foreach ( $matches[1] as $matchNo => $match ) {
$fullTag = $match[0];
$tagBegin = $matches[2][$matchNo][0];
$offset = $match[1];
/*
echo "Full: $fullTag\n";
echo "TagBegin: $tagBegin\n";
echo "offset: $offset\n";
echo "length: ".strlen($fullTag)."\n";
*/
$key = $counter; //$tagBegin.'_'.$counter;
$htmlTagMap[$key] = array(
'full' => $fullTag,
'offset' => $offset
);
$text = substr_replace($text,"<$key>",$offset-$shortened-1,strlen($fullTag)+2);
$shortened += strlen($fullTag) - 1;
$counter++;
}
}
// Jetzt suchen wir von der gewünschten Stelle
// an die nächstmögliche Trennstelle nach links,
// damit wir die Maximalgrenze nicht überschreiten.
// Die Suche ist iterativ, wobei bei jedem
// gefundenem Entity die Maximallänge um die
// Länge des Entities erhöht wird.
$reachedLength = 0;
$rightText = $text;
$summedLengthOfGarbage = 0;
$left = "";
do {
preg_match('/^.*?(&[a-z]+;)/si', $rightText, $matches, PREG_OFFSET_CAPTURE);
if ( $matches ) {
$newText = $matches[0][0];
$tagLength = 0;
$entityLength = strlen($matches[1][0]);
// Wie viele HTML-Tags sind enthalten und
// wie lang sind sie?
preg_match_all("/<\d+>/i", $newText, $tagMatch);
if ( $tagMatch ) {
foreach ( $tagMatch[0] as $tag ) $tagLength += strlen($tag);
}
$newLength = $reachedLength + strlen($matches[0][0]) - $entityLength + 1 - $tagLength;
$left .= $matches[0][0];
$reachedLength +=
strlen($matches[0][0]) /* Eigentliche Länge des neuen Textes */
- $entityLength /* minus der Länge des Entitys am Ende */
+ 1 /* + 1, weil das Entity ja für ein Zeichen steht */
- $tagLength /* minus der Länge aller HTML-Tags */;
$summedLengthOfGarbage += $entityLength - 1 + $tagLength;
$rightText = substr($rightText,strlen($matches[0][0]));
// Falls wir nun weit genug sind,
// schneiden wir das Entity noch
// ab und beenden die Schleife.
if ( $newLength > $length ) {
$summedLengthOfGarbage -= $entityLength - 1; // <- das schneiden wir ja gerade wieder ab
$left = substr($left,0,-$entityLength);
break;
}
} else {
break;
}
} while ( $reachedLength < $length );
// Falls kein Entity vorhanden ist, schneiden wir direkt vom
// Gesamttext die Wörter ab.
if ( $reachedLength == 0 ) {
$left = $text;
}
if ( strlen($left) > $length ) {
// Falls das Wort nun immer noch zu groß
// ist, können wir problemlos vom Ende
// ganze Wörter abschneiden, da es sich
// nicht um Entities handeln kann und
// auch HTML-Tags nun "Wörter" sind.
while ( strlen($left) - $summedLengthOfGarbage > $length ) {
$left = preg_replace('/(.*)[\b\s].+?$/si', "\\1", $left);
}
}
// Nun können wir die HTML-Tags wiederherstellen
preg_match_all("/<(\d+)>/s", $left, $matches);
foreach ( $matches[1] as $match ) {
$left = str_replace("<$match>",'<'.$htmlTagMap[$match]['full'].'>',$left);
}
// Durch das Abschneiden des Textes können nun
// einige Tags nicht mehr geschlossen sein.
// Diese müssen wir, wenn gewünscht, finden
// und manuell schließen.
if ( $closeTags ) {
preg_match_all("#<(/?[a-z]+)[^>]*>#i",$left,$matches);
if ( $matches ) {
$open = array();
foreach ( $matches[1] as $match ) {
if ( $match[0] == "/" ) {
$index = getLastIndex($open,substr($match,1));
if ( $index != -1 ) {
unset($open[$index]);
}
} else {
$open[] = $match;
}
}
$open = array_reverse($open);
foreach ( $open as $tag ) {
$left .= "</$tag>";
}
}
}
return $left;
}
// Hilfsfunktion für shortenText()
function getLastIndex($array,$needle) {
$index = -1;
foreach ( $array as $idx => $element ) {
if ( $element == $needle ) $index = $idx;
}
return $index;
}
?>
Snippetdetails
- hinzugefügt: 25.11.2008
- aktualisiert: 25.11.2008
- Snippet herunterladen
Kommentar verfassen
Fehler gefunden? Doofer Code? Ein kleines "Danke!"? Hinterlasse einfach einen Kommentar.
Dein Kommentar wird erst nach einer manuellen Prüfung angezeigt.