Tronquer un texte avec PHP sans couper les mots

Indispensable pour éviter le duplicate content

par

10 commentaires

Php Elephant

Comment faire pour tronquer (couper) proprement un texte en PHP, sans couper les mots en plein milieu ?

Je vous propose une fonction que j’utilise et qui est très utile pour couper proprement vos textes.

Il est fréquent sur un site Web que l’on cherche à n'afficher qu’une partie d’un texte ou d’une citation, dans un résultat de recherche ou dans un flux RSS par exemple.

Cela permet également de limiter les effets du duplicate content entre les différentes pages d’un site. Si couper un texte est très facile, le tronquer sans césure au milieu des mots est moins aisé et une petite fonction PHP bien optimisée est toujours la bienvenue.

Voici donc comment procéder pour ne pas avoir des coupures de texte en plein milieu des mots :

<?php
/**
* tronquer_texte
* Coupe une chaine sans couper les mots
*
* @param string $texte Texte à couper
* @param integer $nbreCar Longueur à garder en nbre de caractères
* @return string
*/
public function tronquer_texte($texte$nbchar)
{
    return (
strlen($texte) > $nbchar substr(substr($texte,0,$nbchar),0,
    
strrpos(substr($texte,0,$nbchar)," "))." (...)" $texte);
}
?> 

Le premier paramètre est constitué du texte à tronquer, sous forme de chaine. Le second paramètre correspond au nombre de caractères avant la césure.

Et sans endommager le code HTML, c'est possible ?

Le défaut de cette fonction est qu'elle ne respecte pas le balisage HTML. Très pratique pour un texte brut, elle risque de foutre en l'air votre mise en page si le texte comporte du code HTML.

Il est possible de tronquer votre texte tout en conservant l'intégrité du code HTML présent, mais ça se complique.

Voici une fonction qui permet d'arriver au résultat escompté (ce n'est pas moi qui l'ai écrite) :

<?php
/**
* texte_resume
* Coupe une chaine en gardant le formatage HTML
*
* @param string $texte Texte à couper
* @param integer $nbreCar Longueur à garder en nbre de caractères
* @return string
*/
function texte_resume($texte$nbreCar)
{
        
$LongueurTexteBrutSansHtml strlen(strip_tags($texte));

        if(
$LongueurTexteBrutSansHtml $nbreCar) return $texte;

        
$MasqueHtmlSplit '#</?([a-zA-Z1-6]+)(?: +[a-zA-Z]+="[^"]*")*( ?/)?>#';
        
$MasqueHtmlMatch '#<(?:/([a-zA-Z1-6]+)|([a-zA-Z1-6]+)(?: +[a-zA-Z]+="[^"]*")*( ?/)?)>#';

        
$texte .= ' ';

        
$BoutsTexte preg_split($MasqueHtmlSplit$texte, -1,  PREG_SPLIT_OFFSET_CAPTURE PREG_SPLIT_NO_EMPTY);

        
$NombreBouts count($BoutsTexte);

        if( 
$NombreBouts == )
        {
                
$longueur strlen($texte);

                return 
substr($texte0strpos($texte' '$longueur $nbreCar $nbreCar $longueur));
        }

        
$longueur 0;

        
$indexDernierBout $NombreBouts 1;

        
$position $BoutsTexte[$indexDernierBout][1] + strlen($BoutsTexte[$indexDernierBout][0]) - 1;

        
$indexBout $indexDernierBout;
        
$rechercheEspace true;

        foreach( 
$BoutsTexte as $index => $bout )
        {
                
$longueur += strlen($bout[0]);

                if( 
$longueur >= $nbreCar )
                {
                        
$position_fin_bout $bout[1] + strlen($bout[0]) - 1;

                        
$position $position_fin_bout - ($longueur $nbreCar);

                        if( (
$positionEspace strpos($bout[0], ' '$position $bout[1])) !== false  )
                        {
                                
$position $bout[1] + $positionEspace;
                                
$rechercheEspace false;
                        }

                        if( 
$index != $indexDernierBout )
                                
$indexBout $index 1;
                        break;
                }
        }

        if( 
$rechercheEspace === true )
        {
                for( 
$i=$indexBout$i<=$indexDernierBout$i++ )
                {
                        
$position $BoutsTexte[$i][1];
                        if( (
$positionEspace strpos($BoutsTexte[$i][0], ' ')) !== false )
                        {
                                
$position += $positionEspace;
                                break;
                        }
                }
        }

        
$texte substr($texte0$position);

        
preg_match_all($MasqueHtmlMatch$texte$retourPREG_OFFSET_CAPTURE);

        
$BoutsTag = array();

        foreach( 
$retour[0] as $index => $tag )
        {
                if( isset(
$retour[3][$index][0]) )
                {
                        continue;
                }

                if( 
$retour[0][$index][0][1] != '/' )
                {
                        
array_unshift($BoutsTag$retour[2][$index][0]);
                }

                else
                {
                        
array_shift($BoutsTag);
                }
        }

        if( !empty(
$BoutsTag) )
        {
                foreach( 
$BoutsTag as $tag )
                {
                        
$texte .= '</' $tag '>';
                }
        }

        if (
$LongueurTexteBrutSansHtml $nbreCar)
        {
                
$texte .= ' [......]';

                
$texte =  str_replace('</p> [......]''... </p>'$texte);
                
$texte =  str_replace('</ul> [......]''... </ul>'$texte);
                
$texte =  str_replace('</div> [......]''... </div>'$texte);
        }

        return 
$texte;
}
?> 

Cette fonction provient de cette page. J'ai mis un peu de temps pour la trouver c'est la raison pour laquelle je vous la propose ici.

Elle est relativement complexe à coder et je n'avais pas le temps. Dans l'article source, vous trouverez tous les commentaires que j'ai retiré pour aller à l'essentiel : le résultat.

Si vous cherchez à comprendre comment elle fonctionne, lisez l'article original qui est bien documenté.

J'espère que ces deux fonctions PHP vous seront utiles, car ces questions reviennent très souvent sur les forums de discussion.

Si vous avez des questions, vous pouvez les poser en commentaire.

Page rendered in 0.0472 seconds - © Média Camp