regex

ViPHP
ViPHP | 3607 Messages

22 mai 2006, 12:19

bonjour à tous, dnas le but de mettre en forme un texte avec des balises du style bbcode, j'ai fait cette fonction:
function mise_en_forme($texte){
	$texte=str_replace("[gras]","<b>",$texte);
	$texte=str_replace("[/gras]","</b>",$texte);
	$texte=str_replace("[italique]","<i>",$texte);
	$texte=str_replace("[/italique]","</i>",$texte);
	$texte=str_replace("[souligne]","<span style=\"text-decoration: underline;\">",$texte);
	$texte=str_replace("[/souligne]","</span>",$texte);
	$texte=str_replace("[ quote]","<div class=\"quote\">",$texte);
	$texte=str_replace("[/quote]","</div>",$texte);
	return $texte;
}
je voudrait savoir comment l'arranger en faisant qqch du style:
recherche dans $texte [gras]n'importequoiaumilieu[/gras] et remplace le par <b>lemêmen'importequoi</b>
mais je sais pas du tout comment m'y prendre... :(
merci d'avance[/php]

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

22 mai 2006, 16:07

Tu peux utiliser la fonction ereg_replace pour rechercher une expression régulière et la remplacer.

Tu aurais quelque chose du genre
$str = ereg_replace(
  "#\[gras\](.*)\[/gras\]#",
  "<b>$1</b>",
  $str);
le $1 correspondant à ce qui a été capturé par la parenthèse... voir les infos sur les expressions regulières si tu as besoin de plus de détail :) Faudra certainement bricoler un peu pour gérer les paires imbriquées ou non équilibrées...

ViPHP
ViPHP | 1380 Messages

22 mai 2006, 16:26

[-X Tss! Tss! La gourmandise est un vilain défaut!

Et les délimiteurs dans une regex posix...

Punition: lire 10x, et en anglais, Mastering Regular Expressions de Jeffrey Friedl ainsi que Programming Perl de Larry Wall

:wink: :wink:
ripat

Mammouth du PHP | 536 Messages

22 mai 2006, 16:35

je n'ai pas très bien compris ta question, mais si il s'agit de faire de la mise en forme de texte, je peux te proposer cette solution :

une premiere page :

Code : Tout sélectionner

html> <head> <title>essai</title> </head> <body> <form method="post" action="inter.php"> <input type=textearea rows=4 name="texte"><br> Gras : <input type=checkbox name="gras"><br> Italique : <input type=checkbox name="italique"><br> Taille : <input name="taille"><br> <select name="couleur"> Couleur : <option value="black">Noir</option> <option value="blue">Bleu</option> <option value="white">Blanc</option> <option value="green">Vert</option> <option value="red">Rouge</option> </select> <input value="Envoyer" type="submit"> </form> </body> </html>
et une deuxieme page php avec le code suivant :
<?
// Permet de mettre en forme un texte en fonction de plusieurs parametres...
//
//recuperation des parametres
//
$texte=$_POST['texte'];

if(isset($_POST['gras']))
{$gras=$_POST['gras'];}else{$gras="off";};

if(isset($_POST['italique']))
{$italique=$_POST['italique'];}else{$italique="off";};

$taille=$_POST['taille'];
$couleur=$_POST['couleur'];
?>

<html><head><title>essai</title></head>

<body <?
if($couleur!=NULL)
{echo "text=$couleur";};?>>

<?
// suivant les valeurs des variables, on genere les balises HTML qui correspondent, <b> gras, etc...
if($gras=="on")
{echo "<b>";};

if($italique=="on")
{echo "<i>";};

if($taille!="")
{echo "<font size=\"$taille\">";};

/affichage du texte
echo "$texte";

//meme travail qu'au début mais avec fermeture des balises...
// attention ordre inverse de l'ouverture...

if($taille!="")
{echo "</font>";};

if($italique=="on")
{echo "</i>";};

if($gras=="on")
{echo "</b>";};
?>
</body>
</html>
voila, je sais pas si ca t'as aidé
Un prof désespéré à son élève :
- Et maintenant, dessinez-moi un cercle au tableau... Voila... Alors qu'est-ce que c'est?
- Ben un cercle ?
- Non, c'est votre note, sortez !!

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

23 mai 2006, 12:00

Et les délimiteurs dans une regex posix...
J'ai pas bien compris ? c'était par rapport à l'expression que j'ai donné que tu disais ça ?
J'ai collé des # comme délimiteurs, normalement ca marche pareil que le / sauf que j'ai pas à échapper les slash à l'interieur de ma chaine, nan ?

ViPHP
ViPHP | 1380 Messages

23 mai 2006, 12:24

T'a déjà tout lu 10x? :wink:

Non, plus sérieusement, quand tu mets des délimiteurs dans une fonction d'expression rationnelle POSIX comme ereg() ou ereg_replace() ils seront pris comme caractères littéraux.

Les délimiteurs ne sont nécessaires que dans les fonctions PCRE preg_match() et toute sa famille.

Ensuite, tous les quantificateurs comme * dans ton motif sont gourmands, ils prendront donc tous les caractères jusqu'au dernier [/gras] du texte.

Pour reprendre ton masque, tu pourrais faire:
$str = "Je suis [gras]gras[/gras], gros et [gras]gluant[/gras]";

$str = preg_replace(
  "#\[gras\](.*)\[/gras\]#U",
  "<b>$1</b>",
  $str);
echo $str;
Essaye sans l'option "quantificateur non-gourmand" U (derrière le délimiteur) et tu verras de suite la conséquence de la gourmandise. :wink: :wink:
ripat

ViPHP
ViPHP | 3607 Messages

23 mai 2006, 12:30

merci à tous pour vos réponses...
ça marche désormais, mais je n'ai pas bien compris Ripat, sans le U dnas le masque, j'ai quelques balises fermantes ([/..]) qui ne sont pas traduites...
et avec le U tt est comme y faut?

ViPHP
ViPHP | 3607 Messages

23 mai 2006, 12:42

bon finallement j'en ai pas tout à fait finit, avec la gourmandise...
j'essaye d'adapté la solution donnée plus haut, pour transformé les adresses email en mailto, pour cela j'ai "piqué" le masque proposé dans la faq, voici ce que j'ai:
$masque="#^[^-_\.][a-z0-9-_\.]+[^-_\.]@[^-_\.][a-z0-9-_\.]+[^-_\.]\.[a-z]{2,4}$#U";
$remplace="<a href=\"mailto:$1\">$1</a>";
$texte = preg_replace($masque,$remplace,$texte);
mais je ne sais pas où mettre le *?
Modifié en dernier par jojolapine le 23 mai 2006, 14:13, modifié 2 fois.

ViPHP
ViPHP | 1380 Messages

23 mai 2006, 13:02

Le *, comme le + ou un {2.4} sont tous des quantificateurs.

Dans ton masque, il n'est pas indispensable de rendre les quantificateurs non-gourmands.

Par contre ton masque est un masque de validation d'adresse email. Avec les ancrages ^et $, il ne capturera donc pas une email noyée dans un texte.

Retire-les.

De plus, dans l'argument remplacement, tu appelles la référence arrière $1 qui n'existe pas puisqu'il n'y a pas de parenthèses capturantes. Elle ne sont pas, strictement, nécessaires mais il faut alors changer tes références arrières en $0 - la concordance complète.
ripat

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

23 mai 2006, 13:04

Voici une solution qui centralise une base de codes bbcode/html avec une conversion automatique selon le contenu de la base

Cette solution utilise preg_replace pour convertir les codes.
<?php 
echo mise_en_forme("[gras]texte en gras[/gras] texte normal [italique]texte en italique[/italique]
 texte normal [souligne]texte souligne[/souligne] texte normal [ quote]texte style quote[/quote]");

function mise_en_forme($texte){
	//Base de données des tags bbcode/html
	$tags = array (
		array ("bbcode_d"=>"gras", 
				"bbcode_f"=>"/gras",
				"html_d"=>"b",
				"html_f"=>"/b"),
		
		array ("bbcode_d"=>"italique",
				"bbcode_f"=>"/italique" ,
				"html_d"=>"i",
				"html_f"=>"/i"),
		
		array ("bbcode_d"=>"souligne", 
				"bbcode_f"=>"/souligne", 
				"html_d"=>"span style='text-decoration: underline;'",
				"html_f"=>"/span"),
		
		array ("bbcode_d"=>" quote", 
				"bbcode_f"=>"/quote",
				"html_d"=>"div class='quote'",
				"html_f"=>"/div")
	);
	
	//Conversion bbcode/html
	foreach ($tags as $tag) {
    	$bbcode_d = $tag["bbcode_d"];
    	$bbcode_f = $tag["bbcode_f"];
		$html_d = $tag["html_d"];
		$html_f = $tag["html_f"];
		$texte = preg_replace("#\[$bbcode_d\](.*)\[$bbcode_f\]#","<$html_d>$1<$html_f>",$texte); 
	}
    return $texte; 
}
?>
<style>
.quote {padding-left:20; background:silver; color:blue; border-style:solid; border-width:1px; font-style:italic; font-size:14}
</style>
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 3607 Messages

23 mai 2006, 13:10

Par contre ton masque est un masque de validation d'adresse email. Avec les ancrages ^et $, il ne capturera donc pas une email noyée dans un texte.
justement, comment faire pour que ce masque capture l'adresse email, en faisant ça ça marchepas:
$remplace="<a href=\"mailto:$1\">$1</a>";
$masque="#[-_\.][a-z0-9-_\.]+[-_\.]@[-_\.][a-z0-9-_\.]+[-_\.]\.[a-z]{2,4}#";
$texte = preg_replace($masque,$remplace,$texte);
Modifié en dernier par jojolapine le 23 mai 2006, 14:14, modifié 1 fois.

ViPHP
ViPHP | 1380 Messages

23 mai 2006, 13:24

Un truc du genre:
$texte = preg_replace("#[^-_\.][a-z0-9-_\.]+[^-_\.]@[^-_\.][a-z0-9-_\.]+[^-_\.]\.[a-z]{2,4}#","<a href=\"mailto:$0\">$0</a>", $texte);
Sadeq --> La fonction est élégante mais, même remarque, ton quantificateur est gourmand. Et, de plus, ton dot dans (.*) ne prendra pas les retours lignes.

Si tu as un texte comme:

Code : Tout sélectionner

[gras]Premirère ligne en gras... et la deuxième[/gras]
Ton motif s'arrêtera au retour ligne.

Je corrigerais ton masque comme ceci:
$texte = preg_replace("#\[$bbcode_d\](.*)\[$bbcode_f\]#Us","<$html_d>$1<$html_f>",$texte);
Avec les options Uet s
ripat

ViPHP
ViPHP | 3607 Messages

23 mai 2006, 13:32

merci pour la réponse, Ripat, y a un petit quelquechose qui va pas, j'ai un espace capturé au début de chaque adresse e-mail, et vu que pige pas grand chose... :oops:
et au fait, pourquoi on récupère avec $0 la capture alors que plus haut on récupère avec $1
sinon je quémande une denière fois, tjrs depuis la faq, j'ai récupéré ce masque:

Code : Tout sélectionner

#^(?:(?:https?|ftp)://)?(?:w{3}\.)?[^\W]?[\w-\.]*[^\W]?\.[a-z]{2,4} (?:/(?:~?[^\W]?[\w-\./]*[^\W]?(?:\.[a-z]{2,4})?(?:\?\w+=\w+(?:(?:&|&)\w+=\w+)*)?)?)?$#i
et comme tu t'en doute, je n'arriva pas à le faire marcher dans un preg_replace avec capture
merci d'avaance
Modifié en dernier par jojolapine le 23 mai 2006, 14:16, modifié 1 fois.

ViPHP
ViPHP | 1380 Messages

23 mai 2006, 13:41

Pour l'espace, remplace la première classe de caractères [^-_\.] par l'assertion simple \b (séparateur de mots)

preg_replace("#[^-_\.]... ---> preg_replace("#\b...

Pour tes autres question, il serait utile que tu passes un peu de temps sur un tuto de base sur les regex. C'est dur à avaler au début mais c'est un bon investissement. Les regex sont utilisées dans quasiment tous les langages informatiques.

La paternité des expressions relationnelles modernes revient à Larry Wall, linguiste de fprmation et concepteur de Perl.
Modifié en dernier par Ripat le 23 mai 2006, 13:45, modifié 1 fois.
ripat

ViPHP
ViPHP | 3607 Messages

23 mai 2006, 13:44

merci pour l'espace ça fonctionne !
par contre je galère pour les adresses web :-(
je vous jure que c'est la dernière chose que je demande, après je prendrait un tutos sur les expressions régulières, mais en cemoment, j'ai pas le temps, c'est les partiels et je doit en même temps présenter ce projet, alors bon ...
merci d'avance