IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Avis aux expérimentés ! REGEX complexes.. [RegEx]


Sujet :

Langage PHP

  1. #1
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut Avis aux expérimentés ! REGEX complexes..
    bonjour,

    J'ai un véritable dilemne !
    Je vais essayer de poser le problème du mieux que possible (si j'oublie un élément, faites le moi savoir).

    Donc voila je m'explique: je souhaite rechercher un élément interdit (balise bbcode) se trouvant entre deux autres balises bbcode.
    Les exemples permettrons d'illustrer:

    *cas valable:
    [p]Super texte !![/p][hr/]

    *cas non valable:
    [p]Super texte !![hr/][/p]

    Sachant que le [hr/] peut être positionné n'importe ou:
    [p]Super [hr/]texte !![/p]

    J'ai donc fais cela:
    $text = preg_replace('`\[p\](.+)(\[hr\/\])(.+)\[\/p\]`Us', '[p]$1[HR/]$3[/p]', $text);
    mais le problème qui se pose est le suivant:
    si j'ai:
    [p]Super texte !![/p]
    [hr/]
    [p]Super texte !![/p]

    il va me le prendre en compte car il prend le premier [p] et le dernier [/p].
    De plus j'aimerais pouvoir lui dire soit [hr/] soit par exemple [br/]. Je n'ai pas réussi à intégrer le "OU".

    Voila ! en espérant pouvoir trouver de l'aide.
    Merci.

  2. #2
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    Pour le OU, as tu essayé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $text = preg_replace('`\[p\](.+)\[(hr|br)\/\](.+)\[\/p\]`Us', '[p]$1[$2/]$3[/p]', $text);
    ?

    J'ai donc fais cela:
    ...
    mais le problème qui se pose est le suivant:
    ...

    il va me le prendre en compte car il prend le premier [p] et le dernier [/p].
    De plus j'aimerais pouvoir
    Le "de plus" laisse a penser que tu as 2 problemes... mais j'ai pas du comprendre le 1er ;o)

  3. #3
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    le second tu y as répondu ! je pensais que ça serait autre chose mais finalement non...(merci)

    Le premier et le plus important est:
    mais le problème qui se pose est le suivant:
    si j'ai:
    [p]Super texte !![/p]
    [hr/]
    [p]Super texte !![/p]
    il va me le prendre en compte car il prend le premier [p] et le dernier [/p].
    C'est à dire que ma regex regarde entre le premier [p] et le dernier [/p], or dans la citation ci-dessus le [hr/] est bien placé, étant donné qu'il n'est pas entre un [p] [/p], malheureusement il me le prend tout de même.

    Donc le truc c'est de lui forcer la recherche entre [p] et le premier [/p] venu sachant que le [hr/] peut etre n'importe ou entre [p] [/p] (soit juste après le [p], juste avant le [/p], autre..).

    Ca va je suis assé explicite ?

  4. #4
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    ok, en fait, ce qu'il faut verifier, c'est qu'entre le [p] et le [hr/], tu n'a pas de [p/] (ni de [hr\] evidement);o)


    donc qqchose du genre [^...].

    A noter que si tu peut te contenter de la regle : aucune autre balise entre [p] et [hr/], ce qui veux dire en gros que tu n'a pas de balise imbriquées, tu peux facilement faire :

    $text = preg_replace('`\[p\]([^\[]+)\[(hr|br)\/\](.+)\[\/p\]`Us', '[p]$1[$2/]$3[/p]', $text);

    Si par contre, tu veux gerer les balises imbriquées... c'est un peu plus complexe (et pas forcement faisables, toujours eu du mal avec ces cas la ;o)

    en tout cas il faudrait remplacer le permier (.+) par qqchose comme :
    ([^\[]+(\[)?(([^p]|[^h][^r])([^\]])*\])?[^\[]*)

    eventuellement en conditionnant le bloc de la 3eme parenthese ouvrante par le fait d'avoir trouvé qqchose dans la 2eme parenthese (ca existe, mais je m'en souvient plus sur le moment)

    La derniere solution n'est absoluement pas garantie, aussi bien c'est n'importe quoi ;o)))

  5. #5
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    Ta première regex ne fonctionne que dans le cas où j'ai
    [p][hr/]texte[/p]
    pas dans les autres: [p]texte[hr/][/p] ou [p]texte[hr/]long[/p]

    Je ne comprends pas cela: ([^\[]+)
    juste le premier [, pourquoi ? après le ^ ça veut dire que c'est "interdit" !

    Peut etre faire trois regex pour les trois cas ? (pas trop lourd ?)

  6. #6
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    bah, j'ai mis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $text = preg_replace('`\[p\]([^\[]+)\[(hr|br)\/\](.+)\[\/p\]`Us', '[p]$1[$2/]$3[/p]', $text);
    car dans ton code original, tu avait (.+)

    maintenant, si tu veux gerer le cas ou il n'y a aucun texte entre 2 balises, il suffit de remplacer les + par des * ;o)

    [^\[]+ veux dire :
    une liste non vide de caracteres qui ne sont pas [

    ? veux dire 0 ou 1 occurences
    + veux dire 1 ou n occurences
    * veux dire 0 ou n occurences

  7. #7
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    Non ! Pas aucun texte, regarde bien les exemples que j'ai mis !
    Là ça ne foncitonne que si:
    [p][hr/]text[/p]

    or normalement il faudrait aussi cela:
    [p]text[hr/][/p] -> soit le hr à la fin
    [p]text[hr/]mileu[/p] - soit le hr n'importe ou !

  8. #8
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    pour moi, une balise c'est un texte délimité par [ et ]
    donc sur le texte : [p][hr/]text[/p]

    y a un endroit ou il n'y a aucun texte (entre [p] et [hr/])

    remplacer les + par * devrait fonctionner pour tout les cas

  9. #9
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    bah non:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      $text = preg_replace('`\[p\]([^\[]*)\[(hr|br)\/\](.*)\[\/p\]`Us', '[p]$1[HR/]$3[/p]', $text);
    ne fonctionne pas dans les cas cités si dessus !

  10. #10
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    bon, je confirme que ca marche ;o)

    c'est juste que tu ne fait pas ce que tu veux faire je pense ;o)

    Qu'est censé faire ton code ? enlever les [hr/] quand ils sont entourés de [p][p/] ?

    car actuellement, on fait un preg_replace d'une chaine d'un certain format... et on la remplace par... exactement la meme chose ;o) donc tu as l'impression qu'il ne fait rien, mais ce n'est pas le cas ;o)

    essaye avec ce code, qui remplace par de l'html, tu verras que ca fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
     
    function process($text) {
    	$text = preg_replace('`\[p\]([^\[]*)\[(hr|br)\/\](.*)\[\/p\]`Us', '<p>$1<$2/>$3</p>', $text);
    	return $text;
    }
     
    echo process("[p]a[hr/]b[/p] ");
    echo "<br>=========<br>";
    echo process("[p][hr/]b[/p] ");
    echo "<br>=========<br>";
    echo process("[p]a[hr/][/p] ");
    echo "<br>=========<br>";
    echo process("[p]aaa[hr/]bbb[/p] ");
     
    ?>

  11. #11
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    Effectivement ton exemple fonctionne bien, apparement ce qui posserais problème ce sont les saut de ligne ! Je récupère directement le texte de ma base de données et les données sont constitué ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    [p]
    [hr/]
    [b]TITRE:[/b][hr/]
    [br/]TEXTE
    [hr/]
    [/p]
    Je ne vois que cela comme explication ! Y a t-il une solution possible ?

  12. #12
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    le fait qu'il y a des retours chariot n'est pas genant puisque c'est géré par l'option "s" positionnée apres l'option "U".

    Par contre, ce que je vois, c'est que tu as plusieurs [hr/] et [br/] a remplacer !!! Or, l'expression reguliere n'en remplace qu'un !! (le premier)

    Tu peux faire une boucle si tu veux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function process($text) {
    	$oldTexte = "";
    	while ($oldTexte != $text) {
    		$oldTexte = $text;
    		$text = preg_replace('`\[p\](.*)\[(hr|br)\/\](.*)\[\/p\]`Us', '[p]$1<$2>$3[/p]', $text);
    	}
    	return $text;
    }
     
    $var = "
    [p]
    [hr/]
    [b]TITRE:[/b][hr/]
    [br/]TEXTE
    [hr/]
    [/p]
    ";
     
    echo process($var);
    parce que je sais pas gerer les "listes de resultats" en regex, surtout quand il faut les modifier ensuite... y a peut etre un moyen en construisant une chaine contenant un nombre max de resultat (style 99) mais bon...

    A noter que le remplacement proposé ici ne remplace pas [p]... et c'est voulu car on en a besoin pour l'iteration suivante de la boucle...

  13. #13
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    a noter que tu as encore une autre solution...

    un poil plus complexe ;o)))

    je ne resiste pas a te la donner, tu pourras voir par toi meme ;o)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function process2($text) {
    	return preg_replace_callback(
    				'`\[p\](.*)\[\/p\]`Us', 
    				create_function(
    					'$contenu',
    					'return "<p>".preg_replace("`\[(hr|br)\/\]`Us", "<$1>", $contenu[1])."</p>";'
    				),
    				$text);
    }
     
    $var = "
    [p]
    [hr/]
    [b]TITRE:[/b][hr/]
    [br/]TEXTE
    [hr/]
    [/p]
    ";
     
    echo process2($var);
    je l'ai testée et elle fonctionne ;o)
    on evite la boucle, mais y a 2 appels a preg ;o)

  14. #14
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    Waouh !
    La seconde est effectivement un peu plus complexe !
    La première je la comprends et est niquel !
    Maintenant que vaut-il mieux faire ? (niveau ressource, vitesse ?)

    Est-il possible de commenté un peu la seconde !?
    Demain je regarde dans la doc officiel de php ce qu'est la fonction preg_replace_callback, là je commence à tomber un peu

    En tout cas je te remercie beaucoup de ton aide !!!!!!!
    A demain.

  15. #15
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    La seconde est a mon avis plus rapide ;o)

    preg_replace_callback a 3 arguments :
    * Le pattern de recherche
    * une fonction
    * Le texte ou rechercher

    Ici, j'ai mis
    en pattern, ce qui veux dire qu'elle va rechercher toutes les chaines correspondant au masque, c'est a dire toutes les chaines comprises entre les balises [p] et [/p].

    Lorsque le texte aura été trouvé, la methode va construire un tableau :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $tab=array(
    0=> '....', // la chaine complete du texte
    1=> '....', // la chaine correspondant a la 1ere parenthese capturante
    ..
    );
    et va appeler la fonction définie dans le 2eme parametre avec ce tableau.

    Ici, j'ai utilisé une fonction anonyme (c'est a dire déclarée dans le code meme, sans nom) grace a create_function qui prend 2 arguments :
    * La liste des parametres (ici j'ai une variable que j'ai appelé $contenu)
    * Le corps de la methode sous forme de chaine

    Il est tres important que les 2 parametres soient entourés de ' car il ne faut surtout pas que la variable $contenu soit interprétés par exemple.

    Le corps de la methode contient donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return "<p>".preg_replace("`\[(hr|br)\/\]`Us", "<$1>", $contenu[1])."</p>;
    donc on va retourner une chaine <p>...</p>
    ou toutes les occurences dans $contenu[1] (c'est a dire le contenu de la 1ere parenthese capturante ;o) de [hr/] ou [br/] sont remplacés par <hr> ou <br>

  16. #16
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    Impeccable ! J'ai tout compris et appris deux nouvelles fonctions !
    MERCI BEAUCOUP !! (rare de tomber sur des personnes comme toi, c'est encourageant !)
    -> merci pour ces explications PARFAITES !!!!

    Une question dans la deuxième fonction process2(), à la place de faire appel à preg_replace, la fonction str_replace() ne serait-elle pas plus rapide ? (en lui faisant passer un tableau ?)

    Merci encore !

  17. #17
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    oui, tu peux utiliser str_replace, et en effet ca sera un petit peu plus rapide ;o)

  18. #18
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    En tout cas je te remercie beaucoup pour ton aide ! c'est sympa !

    Et tu as remporté avec GRAND succès ce dilemne !

    merci, merci, merci !!!!!!!

  19. #19
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 300
    Points : 93
    Points
    93
    Par défaut
    J'en profite encore !

    J'ai fais cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $text = preg_replace('`\[url=(.+)\]\[\/url\]`Us', '[URL=$1]VIDE[/URL]', $text);
    Seulement le soucis qui ce pose est que lorsque j'ai ça:
    salut]

    En effet il me prend le dernier ], est-il possible de lui indiquer de s'arreter au premier ] ? j'ai fais quelques tests avec ^], mais bon soit ce n'est carément pas ça, soit je le place mal. un petit coup de mains encore ?

  20. #20
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    oui, y a moyen :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $text = preg_replace('`\[url=([^\]]+)\]\[\/url\]`Us', '[URL=$1]VIDE[/URL]', $text);

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. avis aux amateurs(trices) de la SDL !!
    Par iss942001 dans le forum C
    Réponses: 2
    Dernier message: 13/06/2005, 17h43
  2. Réponses: 4
    Dernier message: 04/03/2005, 10h42
  3. Avis aux experts : accéder aux dimensions d'un tableau.
    Par poulpi dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 25/11/2004, 09h09
  4. avis aux experts-Quels sont les logiciels les plus adaptés??
    Par chouchouappc dans le forum Décisions SGBD
    Réponses: 46
    Dernier message: 20/07/2004, 21h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo