Expressions regulières avec exceptions

Eléphant du PHP | 337 Messages

18 févr. 2012, 14:59

Bonjour à tous,

J'essaye depuis un moment de transformer une chaîne de la façon suivante : séparer la chaîne en mots avec les espaces et les traits d'union comme délimiteurs, tout mettre en minuscule, puis chaque première lettre en majuscule, sauf si le mot est l'un des mots suivants : "les", "le", "la", "de", "des", "du", "sur","sous", et enfin retourner la chaîne intiale ainsi modifiée, avec les espaces et traits d'union à leurs places initiales.

Ce qui donnerait par exemple : magie_du_php("saint-MARTIN Sur-LE kloug") => "Saint-Martin sur-le Kloug"

J'ai essayé plein de trucs compliqués à base de str_split(), de preg_split() et autre explode() et substr(), mais je n'y parviens pas. J'imagine qu'il doit y avoir quelque chose à faire avec preg_replace, mais décidément, je n'arrive pas à maîtriser les expressions régulières...

Merci pour votre aide !

ViPHP
ViPHP | 2287 Messages

18 févr. 2012, 15:37

Hello,

preg_split() est bien adapté pour faire un explode() avec plusieurs caractères de séparation possible (ce qui répond déjà à 50% de ta demande). Où en es-tu arrivé avec cette fonction ? :)
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 343 Messages

18 févr. 2012, 18:28

Ou un petit coup d'ucwords
Développeur web

Eléphant du PHP | 337 Messages

18 févr. 2012, 22:02

ucwords() est une fonction pratique effectivement, je ne connaissais pas !

Pour le moment j'en suis bêtement là :
function MEF_MAJmin($chaine)
{
	$chaine = strtolower($chaine);
	$chaine = preg_split("#[ -]#", $chaine);

	$retour = ucfirst($chaine[0]);
	for($i=1 ; $i<sizeof($chaine) ; $i++)
	{
		if($chaine[$i] == "les" || $chaine[$i] == "le" || $chaine[$i] == "la" || $chaine[$i] == "de" || $chaine[$i] == "des" || $chaine[$i] == "du" || $chaine[$i] == "sur" || $chaine[$i] == "sous" || $chaine[$i] == "lès")
			$retour .= " ".$chaine[$i];
		else
			$retour .= " ".ucfirst($chaine[$i]);
	}

	return $retour;
}
Sauf que là ça remplace tous les caractères de séparation par des espaces, je ne sais pas comment récupérer le caractère d'avant, et définir si c'est un tiret ou un espace. Et puis j'ai comme dans l'idée que mon code n'est pas super optimisé (je pressens qu'il doit y avoir moyen de passer par un Array pour les exceptions)

ViPHP
ViPHP | 2287 Messages

18 févr. 2012, 22:39

Sauf que là ça remplace tous les caractères de séparation par des espaces, je ne sais pas comment récupérer le caractère d'avant, et définir si c'est un tiret ou un espace. Et puis j'ai comme dans l'idée que mon code n'est pas super optimisé (je pressens qu'il doit y avoir moyen de passer par un Array pour les exceptions)
Effectivement un petit in_array() peut aider :)

Tu peux aussi te tourner vers l'option PREG_SPLIT_DELIM_CAPTURE de preg_split() pour conserver tes séparateurs.
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 337 Messages

19 févr. 2012, 00:04

J'avais effectivement essayé le paramètre PREG_SPLIT_DELIM_CAPTURE, mais lorsque je l'ajoute, il ne me découpe plus ma chaine selon les séparateurs, il me sort une seule chaîne, la même que celle d'entrée. Ça donnait un truc de ce genre :
$chaine = preg_split("#[ -]#", $chaine, PREG_SPLIT_DELIM_CAPTURE);
echo sizeof($chaine); // Là il me sort 1

$chaine = preg_split("#[ -]#", $chaine);
echo sizeof($chaine); // Là il me sort le bon nombre de mots
Dans la description de la fonction, ils parlent de parenthèses, mais je n'ai pas encore trouvé comment faire.

J'ai essayé également en bidouillant avec le flag PREG_SPLIT_OFFSET_CAPTURE (je voulais faire récupérer le caractère n-1 de la chaîne), mais ça me donne des découpages encore différents :
$chaine = preg_split("#[ -]#", $chaine, PREG_SPLIT_OFFSET_CAPTURE );
echo sizeof($chaine); // il découpe bien selon les espaces, mais pas les tirets
Bref, toujours pas réussi :D

PS : in_array par contre c'est top, très pratique !

ViPHP
ViPHP | 2287 Messages

19 févr. 2012, 00:41

En fait, c'est un petit piège : les options à passer à la fonction preg_split() ne sont pas le troisième paramètre, mais le quatrième :) (le troisième étant une limite d'éléments à séparer, que dans ton cas tu vas vouloir garder à NULL, ou 0, ou -1).

http://fr.php.net/manual/fr/function.preg-split.php

Code : Tout sélectionner

array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )
$chars = preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY);

$chars = preg_split('/ /', $str, -1, PREG_SPLIT_OFFSET_CAPTURE);
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 337 Messages

19 févr. 2012, 00:52

Super classe, ça fonctionne :D
	function MEF_MAJmin($chaine)
	{
		$exceptions = array("les", "le", "la", "de", "des", "du", "sur", "sous", "lès", "dans");

		$chaine = strtolower($chaine);
		$chaine = preg_split("#([ -])#", $chaine, -1, PREG_SPLIT_DELIM_CAPTURE);

		$retour = ucfirst($chaine[0])." ";
		for($i=1 ; $i<sizeof($chaine) ; $i++)
		{
			if(in_array($chaine[$i], $exceptions))
			{
				$retour .= $chaine[$i];
			}
			else
			{
				$retour .= ucfirst($chaine[$i]);
			}
		}

		return trim($retour);
	}
Louée soit ta coquille Caliméro !

ViPHP
ViPHP | 2287 Messages

19 févr. 2012, 01:02

Bravo à toi :D
Louée soit ta coquille Caliméro !
Elle est belle celle-là, on ne me l'avait encore jamais faite, je m'en souviendrai :mrgreen: :mrgreen: 8-)

@+
if(!@work()){ Nespresso(); } else { what(); }
______________________________