Page 1 sur 1

Tronquer une phrase tous les X caractères

Posté : 11 janv. 2010, 13:38
par Aureusms
Bonjour à tous,

J'ai fais une petite class pour tronquer une phrase tous les X caractères sans casser les mots :
<?php
class affiche_ligne_tronquee
{
	var $texte = "";
	var $nombre_caractere = 400;
	var $nombre_ligne = 3;
	var $encodage_utilise = "ISO-8859-15";
	
	//utilise dans la fonction retourne_nombre_de_mots ()
	var $nombre_de_mots = 30;
	
	function retourne_ligne_tronquee ()
	{
		//tests des variables utilisateurs
		if (!in_array($this->encodage_utilise,mb_list_encodings()))
			return FALSE;
			
		if (mb_strlen($this->texte,$this->encodage_utilise) <= $this->nombre_caractere)
		{
			$tab_sortie[0] = $this->texte;
			return $tab_sortie;
		}
		else
		{
			//teste des variables utilisateurs
			if (is_numeric($this->nombre_caractere))
				$this->nombre_caractere = intval($this->nombre_caractere);
			else
				$this->nombre_caractere = 400;
				
			if (is_numeric($this->nombre_ligne))		
				$this->nombre_ligne = intval($this->nombre_ligne);
			else
				$this->nombre_ligne = 3;				
			$caractere_maximum = intval($this->nombre_caractere * ($this->nombre_ligne+1));
			
			if (mb_strlen($this->texte,$this->encodage_utilise) > $caractere_maximum)
				$this->texte = mb_substr($this->texte,0,$caractere_maximum,$this->encodage_utilise);
			
			$tab_texte_temp = explode (" ",$this->texte);
			$tab_sortie= array();
			foreach ($tab_texte_temp as $cle => $valeur)
			{
				if (!empty($valeur))
					$tab_texte[$cle] = trim($valeur);
			}
			$nombre_de_ligne = $this->nombre_ligne;
			$i=0;
			$tab_texte_temp = $tab_texte;
			while ($nombre_de_ligne > 0)
			{
				$tab_comptage_mot = $this->retourne_longueur_mot_dans_tableau($tab_texte_temp);
				if (array_sum($tab_comptage_mot) > $this->nombre_caractere)
				{					
					array_pop ($tab_texte_temp);				
				}
				else
				{
					$numero_clef = count($tab_comptage_mot)-1;
					$tab_temp = array_slice ($tab_texte,0,$numero_clef);
					$texte_retour = implode (" ",$tab_temp);
					array_push($tab_sortie,$texte_retour);
					$tab_texte = array_slice ($tab_texte,$numero_clef);
					$nombre_de_ligne--;
					$tab_texte_temp = $tab_texte;
				}
			}
			return $tab_sortie;
		}
		
	}
	
	function retourne_longueur_mot_dans_tableau ($tableau = 'NULL')
	{
		if (empty($tableau))
			return FALSE;
			
		foreach ($tableau as $cle => $valeur)
		{
			$tab_sortie[$cle] = mb_strlen($valeur,$this->encodage_utilise);
		}
		return $tab_sortie;
	}
	
	function retourne_nombre_de_mots ()
	{
		if (empty($this->nombre_de_mots) or !is_numeric($this->nombre_de_mots))
		{
			$this->nombre_de_mots = 30;
		}
		
		$tab_texte_temp = explode (" ",$this->texte);
		$tab_sortie= array();
		foreach ($tab_texte_temp as $cle => $valeur)
		{
			if (!empty($valeur))
				$tab_texte[$cle] = trim($valeur);
		}
		$tab_texte = array_slice ($tab_texte,0,$this->nombre_de_mots);
		$texte_retour = implode (" ",$tab_texte);
		
		return $texte_retour;
	}	
}
?>
Appel de la class :
<?php
$texte_lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet scelerisque convallis. Nulla enim felis, rhoncus pharetra sollicitudin venenatis, facilisis eu erat. Donec volutpat erat vel erat pharetra sed eleifend est tincidunt. Maecenas vestibulum, elit vitae congue rhoncus, dui nunc gravida elit, sit amet porttitor dolor leo a quam. Duis augue odio, aliquam non tempor nec, semper at urna. Ut eget aliquet elit. Donec id fermentum nunc. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque viverra facilisis risus, vitae sagittis lectus mollis at. Nam vestibulum imperdiet nibh et sodales. Mauris urna lorem, gravida sit amet elementum sit amet, hendrerit vitae felis. Donec ipsum nunc, laoreet interdum hendrerit a, iaculis et eros. In egestas ipsum vitae nisi lobortis tincidunt. Praesent non nunc sit amet nulla lobortis ultricies id nec massa. Maecenas tincidunt massa eu magna tempus consectetur. Nunc eget turpis et odio interdum sagittis eget in augue. Vivamus a eros in est luctus viverra et non nisi. Sed posuere mi vulputate erat pellentesque ultricies.

Ut lacus lacus, fringilla vitae sagittis quis, sodales eget ante. Etiam molestie felis est. Maecenas a rhoncus enim. Proin tincidunt velit non quam tempor mattis. Suspendisse faucibus, ante at blandit gravida, ipsum tortor elementum nisl, quis sollicitudin sapien mi et est. Cras aliquet egestas justo, aliquam semper orci tempus non. Proin a elementum sem. Donec lectus odio, posuere eu ornare quis, sagittis vitae urna. Maecenas nunc magna, ultrices quis rutrum at, rhoncus ac erat. Quisque tincidunt leo non odio tincidunt eu consectetur leo lobortis. Mauris neque ipsum, dignissim nec venenatis a, faucibus non leo.

Sed fermentum hendrerit leo a malesuada. Ut facilisis euismod euismod. Proin eu quam vitae turpis tincidunt iaculis. Mauris ac adipiscing metus. Proin malesuada tincidunt justo, at dignissim arcu posuere eu. Pellentesque eu ante a purus suscipit adipiscing. Maecenas nulla arcu, commodo et dictum in, volutpat ut diam. Aliquam nulla nibh, dapibus tincidunt ornare faucibus, condimentum at ipsum. Aenean nisi felis, volutpat nec feugiat et, fringilla at dolor. Phasellus quis lectus nunc. In imperdiet viverra orci in lobortis. Mauris porta faucibus ligula sit amet fermentum.

Nam dolor leo, rutrum a tristique sit amet, elementum non lacus. Suspendisse eu congue massa. Integer ac nisi sed nisl lacinia sodales. Aliquam lobortis fermentum urna, nec posuere lectus faucibus sed. Integer luctus hendrerit ultricies. Pellentesque non mi eget turpis dictum commodo vel sit amet massa. Curabitur lobortis elit eu orci tempor sit amet cursus nulla dignissim. Sed posuere, massa a aliquet pulvinar, ante enim commodo neque, id porttitor magna lacus in libero. Integer vestibulum lectus faucibus lectus porta sed aliquet ante rutrum. Donec congue, turpis quis feugiat eleifend, sapien lacus lobortis felis, ac faucibus risus felis eget urna. Curabitur quis metus lectus, vel porttitor dolor. Praesent sit amet accumsan est. Etiam ac nibh a metus malesuada blandit. Fusce justo leo, dignissim in cursus sed, tempor ac odio. Quisque molestie leo eu sem consectetur dapibus. Suspendisse rhoncus quam vel tellus gravida euismod tempor sapien rhoncus. Donec eget dui enim. Quisque mattis mollis tellus, vel hendrerit arcu bibendum sit amet.

Duis eu erat quis sapien semper semper sed ut diam. Phasellus lacinia lacinia malesuada. Ut elit nunc, ultrices ac venenatis sit amet, interdum a erat. Morbi sodales convallis nisl quis accumsan. Curabitur vitae sem nisl, at aliquet metus. Nulla nec neque nisi, a scelerisque eros. Cras viverra elit in dolor pretium pellentesque ut non dolor. Nullam dictum tristique egestas. Cras iaculis luctus felis, ac consequat lorem blandit ut. Maecenas fermentum gravida adipiscing. Proin nulla massa, sollicitudin sit amet mollis non, semper nec lectus. Aenean adipiscing, lacus sit amet adipiscing consectetur, neque turpis consequat quam, et sollicitudin sapien orci quis neque";
$texte = new affiche_ligne_tronquee;
$texte->texte = $texte_lorem;
$texte->nombre_caractere = 400;
$texte->nombre_ligne = 4;
$tab_retour = $texte->retourne_ligne_tronquee();
foreach ($tab_retour as $cle => $valeur)
{
	echo strlen($valeur).' '.$valeur.'<br />';
}
echo '<br /><br />'.$texte->retourne_nombre_de_mots().'...';		
?>
Note : je n'ai pas mis encore de filtre sur le caractères spéciaux (/r, /n, /...) mais cela devrait venir.
Note2 : Me dites pas que cela existe déjà : c'est probable j'ai pas cherché et j'aime bien réinventer la roue lol. (mais j'ai mis moins de temps à la créer qu'à la chercher)
Note3 : tous commentaires sont les bienvenues.

Edit 11.01.10 : changement str en mb_str (strlen et substr affecté) + ajout du paramètre $encodage_utilise (défaut à ISO-8859-15) + test si encodage présent.
Edit 11.01.10 : ajout de la fonction pour n'afficher que X mots

Re: Tronquer une phrase tous les X caractères

Posté : 11 janv. 2010, 14:04
par Yosh
Hello,

Tu n'utilise pas mb_strlen() au lieu de strlen()?

Re: Tronquer une phrase tous les X caractères

Posté : 11 janv. 2010, 14:13
par Aureusms
Non effectivement : Je suis parti du principe que strlen suffirait vu que l'encodage utiliserai 1 byte par donnée (ISO-8859-1 ou ISO-8859-15 mais pas UTF-8 je pense).
Je pense que le fait de faire cela peut poser problèmes avec d'autres types d'encodage de type chinois ou autres (vu qu'ils sont codés sur 3 bytes si je me souviens bien). Code modifié.

Re: Tronquer une phrase tous les X caractères

Posté : 11 janv. 2010, 14:57
par Yosh
Non effectivement : Je suis parti du principe que strlen suffirait vu que l'encodage utiliserai 1 byte par donnée (ISO-8859-1 ou ISO-8859-15 mais pas UTF-8 je pense).
Je pense que le fait de faire cela peut poser problèmes avec d'autres types d'encodage de type chinois ou autres (vu qu'ils sont codés sur 3 bytes si je me souviens bien). Code modifié.
Héhé, niquel.

Re: Tronquer une phrase tous les X caractères

Posté : 11 janv. 2010, 16:41
par Yosh
Et au passage, il serait peut-être judicieux d'ajouter une méthode pour n'afficher que les n premiers mots suivi de ...

Je dis ça, mais c'est pas obligatoire hein ^^

Re: Tronquer une phrase tous les X caractères

Posté : 11 janv. 2010, 17:21
par Aureusms
Mouais si tu veux pas bon si c'est juste pour afficher X mots avec un "..." à la fin, une simple fonction suffit. Je l'ai ajouter à la classe pour faciliter l'usage (voir modification)

Re: Tronquer une phrase tous les X caractères

Posté : 13 janv. 2010, 04:44
par AB
J'ai pas regardé en détail mais ça me paraît bien long pour le résultat obtenu. C'est donc la même remarque que Ryle dans ce message

D'ailleurs si on voulait adapter la fonction de Ryle pour plusieurs types d'encodages il suffirait de faire
function truncate($string, $size, $encodage = 'utf-8') {

        if (mb_strlen($string, $encodage) <= $size) // pas de modif	
        return $string;

        $string = mb_substr($string, 0, $size, $encodage); // coupe la chaine à la taille max désirée

        // recherche le dernier espace (s'il y en a un)
        $lastSpace = (strrpos($string, ' ')) ? strrpos($string, ' ') : strlen($string);

        // retourne la chaine coupée proprement (au dernier espace), suivi des points de suspension
        return substr($string, 0, $lastSpace) . '...';
}

// Appel de la fonction 

echo truncate($texte,400); // pour de l'utf-8 puisque la variable $encodage = 'utf-8' par défaut dans la fonction
//ou
echo truncate($texte,400,'ISO-8859-15');  // pour de l'ISO-8859-15 puisque la variable $encodage = 'utf-8' par défaut dans la fonction

//et si on a besoin de trouver le nombre de mots contenus dans les 400 premiers caractères d'un texte 'ISO-8859-15'
echo count(explode(' ',truncate($texte,400,'ISO-8859-15')));
A vrai dire je ne vois pas trop l'intérêt d'autres fonctionnalités puisqu'on utilise souvent ça pour faire tenir l'extrait d'un texte dans un espace réservé (donc le nombre de mots n'est pas adapté puisqu'ils sont de longueur variable) mais bon je dois oublier d'autres cas utiles :)

Re: Tronquer une phrase tous les X caractères

Posté : 02 févr. 2010, 17:28
par Hywan
Hey :-),

Si je peux me permettre : qu'elle est la différence avec wordwrap ?

Re: Tronquer une phrase tous les X caractères

Posté : 02 févr. 2010, 17:44
par zeus
Note2 : Me dites pas que cela existe déjà : c'est probable j'ai pas cherché et j'aime bien réinventer la roue lol. (mais j'ai mis moins de temps à la créer qu'à la chercher)

Re: Tronquer une phrase tous les X caractères

Posté : 02 févr. 2010, 20:32
par AB
Hey :-),

Si je peux me permettre : qu'elle est la différence avec wordwrap ?
La différence c'est que wordwrap n'est pas compatible avec un encodage multi-octets comme l'utf-8 par exemple :wink:

Re: Tronquer une phrase tous les X caractères

Posté : 03 févr. 2010, 19:36
par Hywan
Tu transformes alors ta chaîne en octets et tu appliques wordwrap, puis tu fais l'opération inverse :mrgreen:.
Ou sinon, un preg_split avec un support multi-octets aurait peut-être été judicieux ?

Re: Tronquer une phrase tous les X caractères

Posté : 04 févr. 2010, 19:12
par AB
Déjà on peut optimiser la fonction de Ryle que j'ai donné en exemple :
function truncate($string,  $size, $encodage  = 'utf-8')  {

        if (mb_strlen($string, $encodage) <= $size) // pas de modif    
        return $string;

        $string = mb_substr($string, 0, $size, $encodage); // coupe la chaine à la taille max désirée

        // recherche le dernier espace (s'il y en a un)
        $lastSpace = (strrpos($string, ' ')) ? strrpos($string, ' ') : strlen($string);

        // retourne la chaine coupée proprement (au dernier espace), suivi des points de suspension
        return substr($string, 0, $lastSpace) . '...';
}
On remarque que le talon d'Achille de cette fonction est qu'elle recherche la longueur totale de la chaine; ce qui rendra cette fonction d'autant plus lente qu'elle travaillera sur des chaines de plus en plus longues.

On peut donc faire un compromis en faisant :
function truncate2($string, $size, $encodage = 'utf-8') {

        $chaine = mb_substr($string, 0, $size, $encodage); // coupe la chaine à la taille max désirée

	if ($chaine == mb_substr($string, 0, $size + 1, $encodage)) // pas de modif	
        return $chaine;
		
        // recherche le dernier espace (s'il y en a un)
        if ($lastSpace = strrpos($chaine, ' ')) 
	return substr($chaine, 0, $lastSpace) . '...';	
	else 
	return $chaine . '...';
}
La deuxième fonction sera environ deux fois moins rapide sur des chaines très courtes ou encore s'il n'y a rien à tronquer, mais sur un temps de traitement déjà très court puisque les chaines à traiter sont très courtes.

Les deux fonctions s'équilibrent aux alentours de chaines de plus de 300 caractères, et par la suite la différence sera d'autant plus importante que la longueur de la chaine à traiter est importante.
Cela peut aller de plusieurs fois à plusieurs dizaines de fois plus rapide pour la deuxième fonction avec des chaines de plusieurs milliers ou dizaines de milliers de caractères.

Sinon preg_split() à vu de nez je pense pas que ce serait plus rapide, mais si certains veulent tenter leur chance...

Re: Tronquer une phrase tous les X caractères

Posté : 12 févr. 2010, 16:21
par stealth35
pour le regexp y'a un petit article ici
http://blog.macromates.com/2006/wrappin ... pressions/