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 :

Remplacer contenu et balises


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Inscrit en
    Novembre 2009
    Messages
    41
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 41
    Points : 27
    Points
    27
    Par défaut Remplacer contenu et balises
    Bonjour,


    J'ai quelques difficultés avec les regex, je voudrais apprendre à nettoyer une chaine, jusque là lorsqu'il s'agit de texte cela fonctionne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     $contenu = preg_replace('/<span class="stars4 " title="">(.*)<\/span>/isU','bonjour',  $contenu);
    Mais maintenant, je ne comprends pas comment nettoyer une chaine, qui contient des balises différentes par exemple remplacer/supprimer tout ce qui est à l'intérieur de la balise SPAN Nowrap
    Donc DIV - SPAN - STRONG et leur contenu par rien :

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    <span class="Nowrap"> <div class="estimation" alt="4/5">&nbsp;</div><span title="" rel="" class="">&nbsp;</span><strong class="" data-title="">1565</strong> </span>
    J'ai essayé ceci cela ne fonctionne pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     $contenu = preg_replace('/<span class="Nowrap"> (.*)<\/span>/isU',' ',  $contenu);
    Merci de votre aide

  2. #2
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 418
    Points
    91 418
    Billets dans le blog
    20
    Par défaut
    Pourquoi vouloir passer par une expression régulière ? strip_​tags ne te convient pas ?
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  3. #3
    Nouveau membre du Club
    Inscrit en
    Novembre 2009
    Messages
    41
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 41
    Points : 27
    Points
    27
    Par défaut
    La réponse n'est pas adaptée à la question strip_tags enlève les balises mais n'enlève pas les balises et le texte, je cherche une expression régulière pour enlever le tout !

  4. #4
    Membre habitué Avatar de denissay
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 103
    Points : 125
    Points
    125
    Par défaut
    Avec un parseur DOM, c'est beacoup plus aisé car les regex ne sont pas fait pour traiter le DOM... je te conseille PHP Simple HTML DOM Parser...
    Une réponse utile vous a aidé ? N'oubliez pas le
    Votre problème est résolu ? N'oubliez pas le

  5. #5
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Le problème est que quand ta balise <span> cible contient elle-même d'autres balises <span>, il y a ambiguïté sur la balise de fermeture et la première balise fermante rencontrée (vu que tu utilises un quantificateur non glouton) est, du coup, celle qui est choisie au lieu de la balise fermante correspondante.

    Pour y remédier, la solution (regex) est d'utiliser la récursion:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (<span\b[^>]*>(?>[^<]++|<(?!/?span\b)|(?1))*</span>)
    cette pattern plus en détail:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (                      # on ouvre un groupe capturant (le groupe 1)
        <span\b[^>]*>      # le tag d'ouverture
        (?>                # on ouvre un groupe atomique qui décrit le contenu possible entre le tag d'ouverture et de fermeture
            [^<]++         # tous ce qui n'est pas un <
          |                # OU
            <(?!/?span\b)  # un < qui ne soit pas le premier caractère d'une balise ouvrante ou fermante "span"
          |                # OU
            (?1)           # on répète le groupe de capture 1 (c'est ici qu'à lieu la récursion)
        )*                 # on ferme le groupe atomique et on le répète autant de fois que nécessaire (zéro ou plus)
        </span>            # jusqu'à la balise fermante
    )                      # on ferme le groupe capturant
    (NB: on peut remplacer (?1) par (?-1) pour se réfèrer au dernier group capturant ouvert.)

    Pour ton cas précis on aboutit à une pattern du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $pattern = <<<'EOD'
    ~
    # définition de sous patterns
    (?(DEFINE)
        (?<span> (<span\b[^>]*>(?>[^<]++|<(?!/?span\b)|(?-1))*</span>) )  # la sous pattern nommée "span"
    )
    # la pattern principale
    <span \s [^>]*? \b class \s* = \s* "Nowrap" [^>]* > # la balise ouvrante avec la classe Nowrap
    (?> [^<]++ | \g<span> | <(?!/span) )*            # contenu possible
    </span>                              # balise fermante
    ~xi
    EOD;
    Mais le problème avec le html c'est qu'il est difficile de faire une pattern totalement waterproof qui va éviter tous les pièges! Exemples:

    • l'attribut "class" n'est pas forcément entre guillemets doubles
    • l'attribut "class" peut contenir plusieurs valeurs
    • le contenu entre les balises "span" peut contenir un commentaire dans lequel se trouve des balises ouvrantes ou fermantes "span"
    • la balise fermante "</span>" peut tout simplement ne pas exister


    Pour résoudre les deux premier points on peut remplacer "Nowrap" par (?>["'](?:[^"'\s]+\s+)*?\s*)?Nowrap(?:["'\s]|(?=>)).
    Pour éviter les éventuelles balises "span" cachées dans les commentaires il suffit de chercher les commentaires avant les autres balises.

    On obtient alors:
    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
    $pattern = <<<'EOD'
    ~
    # définition de sous patterns
    (?(DEFINE)
        (?<comment> <!--.*?--> ) # la sous pattern pour les commentaires html
        (?<span> (<span\b[^>]*> (?> [^<]++ | \g<comment> | <(?!/?span\b) | (?-1) )* </span>) )  # la sous pattern nommée "span"
        (?<cible> \b class \s* = \s* (?>["'](?:[^"'\s]+\s+)*?\s*)?Nowrap(?:["'\s]|(?=>)) )
    )
    # la pattern principale
    <span \s [^>]*? \g<cible> [^>]* > # la balise ouvrante avec la classe Nowrap
    (?> [^<]++ | \g<comment> | \g<span> | <(?!/span) )*            # contenu possible
    </span>                              # balise fermante
    ~xis
    EOD;
    $contenu = preg_replace($pattern, ' ', $contenu);
    En ce qui concerne l'absence éventuelle de balise fermante, il faut faire un choix sur le comportement à adopter, et le choix le meilleur ne peut se faire qu'en fonction du contexte, mais là, on aboutit à un tout autre type de pattern.
    C'est pour ce genre de subtilités que le traitement du html avec les regexs n'est pas toujours évident à mettre en œuvre.

    L'utilisation du DOM pourrait alors apparaître comme la solution salvatrice, s'il ne présentait pas lui aussi quelques limitations:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $dom = new DOMDocument();
    @$dom->loadHTML($contenu);
    $xpath = new DOMXPath($dom);
    $spanNodes = $xpath->query('//span[contains(@class, "Nowrap")]');
     
    foreach($spanNodes as $spanNode) {
       $spanNode->parentNode->removeChild($spanNode); 
    }
    $contenu = $dom->saveHTML();
    Voilà, c'est un peu plus digeste et proche du langage naturel, quoi que les regex avec un peu de pratique, de présentation, et de commentaires...

    Le soucis avec le DOM c'est qu'il doit construire "l'arbre" du document html avant de pouvoir le traiter (cette étape peut être coûteuse suivant la taille et la complexité du document.). Mais il va devoir procéder à des corrections si le document n'est pas conforme à ce qu'il attend, ce qui peut s'avérer problématique si l'on a l'intention de lui faire traiter des bouts de code html. Par exemple si je lui soumets la chaîne "<span>tata<span>titi</span>toto", celui ci me renverra généreusement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
    <html><body><span>tata<span>titi</span>toto</span></body></html>
    sans que je lui ai demandé quoi que ce soit! Il faut donc se livrer à une acrobatie pour se débarrasser du doctype, des balises html et body, ce qui reste faisable. En revanche, on a absolument aucun contrôle sur la manière dont les balises de fermetures sont rajoutées (automatiquement à la toute fin du noeud parent).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  6. #6
    Membre habitué
    Homme Profil pro
    Directeur technique
    Inscrit en
    Février 2011
    Messages
    146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Directeur technique
    Secteur : Transports

    Informations forums :
    Inscription : Février 2011
    Messages : 146
    Points : 172
    Points
    172
    Par défaut
    CosmoKnack => intéressant ton post, peux tu donner un exemple qui marche avec son cas de figure ? (j'avoue ma méconnaissance de la récursion dans les regex et ça m’intéresse au plus au point)


    sinon j'ai crée une lib pour ce genre de probleme : https://github.com/Esysteme/glial/bl...ct/Grabber.php

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    use \Glial\Extract\Grabber;
    $content = 'text la<span class="Nowrap"> <div class="estimation" alt="4/5">&nbsp;</div><span title="" rel="" class="">&nbsp;</span><strong class="" data-title="">1565</strong> </span> text ici';
    $str = Grabber::getTagContent($content , '<span class="Nowrap"', false);
    $content = str_replace($str, '<span class="Nowrap"></span>', $content );
    echo $content;
    ce qui donne

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    text la<span class="Nowrap"></span> text ici'

  7. #7
    Membre éprouvé Avatar de patrickbaras
    Homme Profil pro
    Informaticien (à sa mémère).
    Inscrit en
    Septembre 2010
    Messages
    525
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : Belgique

    Informations professionnelles :
    Activité : Informaticien (à sa mémère).
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 525
    Points : 1 103
    Points
    1 103
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <?php
    $contenu = '<span class="Nowrap"> <div class="estimation" alt="4/5">&nbsp;</div><span title="" rel="" class="">&nbsp;</span><strong class="" data-title="">1565</strong> </span>';
    $contenu = preg_replace('/(?<=<span class="Nowrap">)(.*?)(?=<\/span>$)/iu','bonjour',  $contenu);
    echo "<xmp>";
    var_dump($contenu);
    echo "</xmp>";
    ?>
    donne
    string(35) "<span class="Nowrap">bonjour</span>"
    ce message vous a aidé ! Un petit click sur fait toujours plaisir

    "Nos études ont montré que la probabilité qu’un programme corrigé fonctionne comme avant la correction est seulement de cinquante pour cent." Bev Littlewood & Lorenzo Strigini

    "Le logiciel, c’est comme le sexe, c’est meilleur quand c’est libre/gratuit." Linus Torvalds

Discussions similaires

  1. Remplacer le contenu de balises à la chaine
    Par matouz dans le forum XML/XSL et SOAP
    Réponses: 0
    Dernier message: 30/10/2014, 10h56
  2. Réponses: 3
    Dernier message: 10/08/2007, 13h45
  3. remplace contenu fichier texte
    Par schumi101 dans le forum C
    Réponses: 20
    Dernier message: 23/06/2006, 15h49
  4. Extraire le contenu des balises XML
    Par calimero2611 dans le forum Modules
    Réponses: 7
    Dernier message: 12/06/2006, 15h09
  5. [HTML] affichage du contenu des balises 'alt' dans une iframe
    Par etarip dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 11/08/2005, 14h08

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