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 :

Faire tourner une RegEx sur l'intégralité d'un fichier


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut Faire tourner une RegEx sur l'intégralité d'un fichier
    Bonjour à tous!

    J'ai un projet en php contenant quelques centaines de fichiers avec du code bien sale. Du bon procédural avec le code HTML mélangé dans des fonctions de traitement, à l'ancienne, avec une mise en page à base de <table>. Bref du bonheur...

    Je souhaite dépoussiérer ce projet (dont je ne suis pas l'auteur) et effectuer un découpage MVC puis une factorisation du code. (courage, courage!)

    La première étape quand je prends un fichier c'est d'effectuer quelques manipulations de base (réécriture des balises HTML en minuscules, réécriture des include() et require(), changement de certaines classes HTML, etc...) Ces manipulations je les effectue à la main et ça me prend 10 bonnes minutes par fichier, et vu le nombre de fichiers... Donc je voudrais créer une routine, à base de RegEx, pour automatiser cette étape.

    J'ai effectué des test, j'arrive a utiliser mes RegEx sur des variables mais pas directement sur mon fichier. Voici comment je procède:

    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    // Dossier source
    $folder = 'MonDossier' . DIRECTORY_SEPARATOR;
    // Fichier source
    $file = 'testFile.php';
    // chemin complet vers mon fichier source
    $path = ROOT . $folder . $file;
     
    // Teste si le fichier existe
    if (file_exists($path)) {
        echo 'Le fichier : "' . $path . '" existe';
    } else {
        echo 'Erreur, le fichier : "' . $path . '" n&apos;existe pas';
    }
     
    // ouverture du fichier en lecture et écriture
    $handle = fopen($path, 'r+');
     
    // REGEX insensible à la casse avec '/i'
    $pattern = '/^(include|require){1}(_once)?[ ]?[\(]?[\'"](.*?)[\'"][\)]?[ ]?;/i';
    $replace = '${1}${2}W ROOT . \'${3}'.'\';';
     
    // Modification du contenu
    $action = preg_replace($pattern, $replace, $handle);
     
    // Ecriture dans le fichier
    $write = fwrite($handle, $action);
     
    // Fermeture du fichier
    fclose($path);
    La seule chose que j'obtiens comme changement sur mon fichier c'est qu'au tout début il apparaît ce message : "Resource id #3" !!

    Je crois que je n'ai pas compris comment on manipule le contenu d'un fichier...

    Voyez-vous d'où vient mon erreur et comment la réparer svp?

    Merci pour votre temps.

  2. #2
    Expert éminent sénior
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 235
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 235
    Points : 15 532
    Points
    15 532
    Par défaut
    quand vous faite "$handle = fopen", la variable contient seulement l'identifiant de la ressource, qu'il faut ensuite parcourir pour lire le contenu du fichier
    Si vous voulez lire le fichier en entier et le réécrire d'un coup je vous conseille de plutot utiliser ces fonctions :
    http://php.net/file_get_contents
    http://php.net/file_put_contents

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    pour ma part, j'utilise Notepad++ :

    • on peut ouvrir plusieurs fichiers en même temps (quelques centaines sans problème)
    • on peut "rechercher" / "remplacer" sur l'ensemble des fichiers ouverts, avec 3 modes de recherche, dont "expression régulière"

    Ce serait dommage de s'en priver....


    N.B. Ne dis pas de mal du "procédural "....

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    tout d'abord merci pour vos réponses.

    @jreaux62 : J'utilise PhpStorm qui a aussi une aide pour les RegEx. Le problème que je rencontre ne vient pas vraiment des RegEx mais plutôt du traitement du fichier.

    @mathieu : J'ai regardé les deux liens que vous m'avez proposé, j'ai fait un test mais ce n'était pas vraiment concluant. Par contre j'obtiens un début de résultat avec file() qui découpe mon fichier dans une table ce qui devrait être pratique pour le traitement ensuite.

    J'ai essayé la technique suivante :
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    // Dossier source
    $folder = 'MonDossier' . DIRECTORY_SEPARATOR;
    // Fichier source
    $file = 'testFile.php';
    // chemin complet vers mon fichier source
    $path = ROOT . $folder . $file;
     
    // Teste si le fichier existe
    if (file_exists($path)) {
        echo 'Le fichier : "' . $path . '" existe';
    } else {
        echo 'Erreur, le fichier : "' . $path . '" n&apos;existe pas';
    }
     
    // découpage du fichier dans un array
    $lines = file($path);
     
    // Pattern de ma REGEX (insensible à la casse avec '/i')
    $pattern = '/^(include|require){1}(_once)?[ ]?[\(]?[\'"](.*?)[\'"][\)]?[ ]?;/i';
    // Remplacement souhaité pour chaque match
    $replace = '${1}${2} ROOT . \'${3}'.'\';';
     
    // boucle pour traiter chaque ligne du tableau
    $aAfter = array();
    foreach ($lines as $line) {
        array_push(
            $aAfter,
            array(
                preg_replace($pattern, $replace, utf8_decode($line))
            )
        );
    }
     
    // Affichage du résultat
    echo '<br>VALEUR APRES TRAITEMENT : <br>';
    var_dump($aAfter);
     
    // Fermeture du fichier
    fclose($path);
    J'ai un début de résultat intéressant, c'est à dire que pour chaque ligne j'ai bien UN traitement qui s'effectue. Malheureusement si sur une ligne j'ai deux match qui correspondent à ma RegEx, seul le premier est remplacé. A ce stade je ne comprends pas trop comment appliquer la même tâche s'il y a plusieurs occurrences.

    Voyez-vous a quel niveau mon raisonnement est biaisé? Peut-être que preg_replace() n'est pas la bonne fonction?

    Je tenterai de remplacer l'intégralité du fichier par le nouveau résultat une fois que celui-ci sera bon, pour le moment je me concentre surtout sur le traitement.

    Merci pour votre attention.

  5. #5
    Invité
    Invité(e)
    Par défaut
    J'utilise PhpStorm qui a aussi une aide pour les RegEx...
    Je ne parlais pas d'aide mais bien de traitement.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $pattern = '/................/Ui';
    U pour 'ungreedy".


  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    @jreaux62 : Bonjour et merci! En effet Notepad++ et PhpStorm font tout les deux du traitement de RegEx, et je les utilise aussi, mais le but de ce que je veux faire avec le code en question c'est d'automatiser plusieurs traitement à suivre. (Environ 5 traitements avec 5 RegEx différentes).
    Je viens de tester l'option de recherche PCRE_UNGREEDY mais je n'ai pas vraiment constaté de différence.

    Mais je ne m'avoue pas encore vaincu.

  7. #7
    Expert éminent sénior
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 235
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 235
    Points : 15 532
    Points
    15 532
    Par défaut
    Vous pouvez nous montrer un extrait de code que vous traitez ?

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    Voilà le début de mon fichier de test. Attention ça pique mais c'est juste pour vérifier que ça 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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    <?php
    /******************************************************************************
     * Auteur         : General_Batton
     * Date version   : 13 Novembre 2017
     * v1.0.0
     ******************************************************************************
     * FICHIER TEST POUR LE TRAITEMENT AUTOMATIQUE AVANT DÉCOUPAGE MVC
     ******************************************************************************/
    // Debut Page
    $Code_Page = 'SFI';
    $Nom_Page = 'MSI_etape1';
    $NomOX = isset($post['NomOX']) ? $post['NomOX'] : null;
    $titre = isset($post['titre']) ? $post['titre'] : null;
    $OperateurName = isset($_SESSION['OperateurName']) ? $_SESSION['OperateurName'] : null;REQUIRE("chemin/fichier.php");Include('chemin/fichier.XML');
    include_once 'chemin/fichier.php';$msg = '';Require_once('chemin/fichier.JS');$Nom_Page = 'MSI_etape1';INCLUDE "chemin/fichier.DOCX";REQUIRE("chemin/fichier.php");
    $tbList = array();
    // test de réécriture pour les INCLUDE et les REQUIRE
    REQUIRE("chemin/fichier.php");
    REQUIRE_ONCE 'chemin/fichier.html';
    Require_Once "chemin/fichier.js";
    Require("chemin/fichier.php");
    Require("chemin/fichier.php");
    Require_once('chemin/fichier.HTML');
    Require_once('chemin/fichier.JS');
    include('chemin/fichier.xml');
    include('chemin/fichier.csv');
    Include('chemin/fichier.XML');
    Include_once('chemin/fichier.PHP');
    include_once('chemin/fichier.xtpl');
    include_once('chemin/fichier.doc');
    include_once 'chemin/fichier.php';
    INCLUDE "chemin/fichier.DOCX";
    INCLUDE_once "chemin/fichier.php";
    include_ONCE "chemin/fichier.php";
    require("design/debutpage.php");
     
    if (empty($DNGpLi)) {
        $title_box = 'ERREUR : AUCUN GROUPE SELECTIONNE';
        require("design/box.php");
        echo $haut_box_orange_ombre;
        echo '<p class=highlight_red><b>Veuillez choisir une groupe SVP !!</b></p>';
        include('design/page_precedente.php');
        echo $bas_box_ombre . '';
    } else {
        // Mise en forme
        $title_box = $titre;
        require("design/box.php");
        echo $haut_box_gray_cartouche;
        echo '<hr color="#FF9933" />';
        Affiche_Liste_NNI($DNGpLi, $Tri, $NumDT, $ServeurUMRA, $PortIP);
        echo '</div></div>';
        echo '<hr><table width="40%" border="0" align="center"><tr align="center">';
        // Bouton rafraichir
        echo '<td><form action="index.php" method="post">';
        echo '<input name="page" type="hidden" value="MSI_etape1" />';
        echo '<input name="Tri" type=hidden value="' . $Tri . '" />';
        echo '<input type="hidden" name="DNGpLi" value="' . $DNGpLi . '" />';
        echo '<img src="../img/webexp/load-white.gif"><input type="submit" value="Actualiser" class="btn_medium" style="background-color:#66CC66" Title="Rafraichir la page" /></form></td>';
        // Bouton Choix tri
        echo '<td><form action="index.php" method="post">';
        echo '<input name="page" type="hidden" value="MSI_etape1" />';
        echo '<Input name="Tri" type="hidden" value="' . $AfficheTri . '" />';
        echo '<input type="hidden" name="DNGpLi" value="' . $DNGpLi . '" />';
        echo '<img src="../img/webexp/picto_tri.jpg" width="20" height="20" /><input type="submit" value="TRI SUR LE ' . $AfficheTri . '" class="btn_large" title="Tri sur le' . $AfficheTri . '" /></form></td>';
        echo '</tr></table>';
     
        echo '<hr color="#FF9933" />';
        echo '<p align=center>';
        echo '<form action="index.php" method="post">';
        echo '<input name="page" type="hidden" value="MSI" />';
        echo '<input type="submit" value="Choix Groupes" class="btn_large" />';
        echo '</form></p><br>';
        echo '</div>';
    }
     
    ?>
    Comme vous pouvez le voir c'est totalement factice. J'attends juste le bon traitement avant de le faire avec mes vrais fichiers.

  9. #9
    Invité
    Invité(e)
    Par défaut
    1- Pour tester te regex en ligne :



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (include|require){1}(_once)?[ ]?[\(]?[\'"]([^;]*)[\'"][\)]?[ ]?;
    2- réglage des options (dans l'input, à droite) :
    • g : global
    • U : Ungreedy
    • i : insensitive
    • m : multiligne

    3- Substitution :
    • \L : en minuscules
    • (\U : en majuscules)
    • \E : fin d'action de \L (ou \U)
    Dernière modification par Invité ; 15/11/2017 à 16h30.

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    Yes!

    Merci jreaux62 ça fonctionne enfin!

    Voilà comment j'ai fait:
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    // Racine du site
    define('ROOT', __DIR__ . DIRECTORY_SEPARATOR);
    // Dossier cible
    $folder = 'ressources' . DIRECTORY_SEPARATOR;
    // Fichier cible
    $file = 'testFile.php';
     
    $path = ROOT . $folder . $file;
    $newPath = ROOT . $folder . $newFile;
     
    // Teste si le fichier existe
    if (file_exists($path)) {
        echo 'Le fichier : "' . $path . '" existe';
    } else {
        echo 'Erreur, le fichier : "' . $path . '" n&apos;existe pas';
    }
     
    // découpage du fichier dans un array
    $lines = file($path);
     
    // Pattern de ma REGEX (insensible à la casse avec '/i')
    // et multiligne avec '/m'
    $pattern = '/(include|require){1}(_once)?[ ]?[\(]?[\'"](.*?)[\'"][\)]?[ ]?;/im';
    // Remplacement souhaité pour chaque match
    $replace = '${1}${2} ROOT . \'${3}'.'\';';
     
    // boucle pour traiter chaque ligne du tableau
    $aAfter = array();
     
    foreach ($lines as $line) {
        array_push(
            $aAfter,
            array(
                preg_replace($pattern, $replace, utf8_decode($line))
            )
        );
    }
     
    // Affichage du résultat
    echo '<br>VALEUR APRES TRAITEMENT : <br>';
    var_dump($aAfter);
    Pour info l'option de recherche /g ne fonctionne pas sous PHP (en tout cas en 5.5.12) ... et j'ai mis longtemps à m'en rendre compte. Je ne comprenais pas le message d'erreur.

    Pour finir j'ai essayé ta technique de substitution avec \L pour les minuscules, mais ça ne fonctionne pas. (j'ai peut-être pas la bonne syntaxe).

    En tout cas merci beaucoup, j'effectuerai le traitement des minuscules en php à part et ça fera bien l'affaire.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Exact... il y a quelques différences entre le tsite de test et son application réelle...

    Pourtant, j'avais bien indiqué dans "FLAVOR" (colonne de gauche) : pcre (php)




    D'autres sont bien plus calés que moi en regex (notamment, si CosmoKnacki passe par là... )

  12. #12
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 093
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 093
    Points : 6 754
    Points
    6 754
    Par défaut
    Sous Firefox, Regex101 a tendance à faire déborder la pile d’appels avec la flavor pcre. C’est un choix de conception étonnant d’avoir tenté d’émuler le moteur PCRE côté client, donc en JS… Pas étonnant qu’il y ait des différences.

    Le drapeau /g ne marche pas avec les fonctions preg_*, car ces dernières existent soit en deux variantes comme preg_match et preg_match_all, soit avec un paramètre optionnel $limit comme preg_replace.

    jreaux62, je ne connaissais pas ces marqueurs \U, \L, on en apprend décidément tous les jours ! Cependant je n’ai pas réussi à les faire fonctionner, ni dans la regex, ni dans la chaîne de substitution. Peut-être que ça ne marche que sous Perl. Je ne connais pas bien Perl et il est indiqué dans la doc de PCRE qu’il y a quelques différences entre le « vrai » moteur Perl et l’implémentation PHP.

    Pour plus de souplesse on peut utiliser preg_replace_callback, c’est une ruse de Sioux que j’avais trouvée dans un livre de Christophe Porteneuve. C’était en JS et il n’y avait pas encore de callbacks en PHP à l’époque, mais les choses ont avancé depuis.

    Ci-dessous un exemple qui met en capitale la première lettre de chaque mot :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var_dump(preg_replace_callback(
      /* pattern  */ '/(\w)(\w*)/i',
      /* callback */ function ($matches) {
                       // matches[0] -> la correspondance entière
                       // matches[1] -> 1er groupe capturant
                       // matches[2] -> 2nd groupe capturant
                       return strtoupper($matches[1]) . $matches[2];
                     },
      /* subject  */ 'voyez ce bon fakir moqueur pousser un wagon en jouant du xylophone'
    ));
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    Bonsoir à tous,

    Merci pour vos réponses.
    @Watilin : il faudrait que je me penche sur la fonction preg_replace_callback() pour comprendre à quoi elle sert et comment elle fonctionne.

    J'ai adapté un peu mon code pour pouvoir effectuer plusieurs traitements à la suite... et ça fonctionne à moitié.

    Voici ce que je fais:
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
    // Racine du site
    define('ROOT', __DIR__ . DIRECTORY_SEPARATOR);
    // Dossier cible
    $folder = 'ressources' . DIRECTORY_SEPARATOR;
    // Fichier cible
    $file = 'testFile.php';
     
    $path = ROOT . $folder . $file;
     
    // Teste si le fichier existe
    if (file_exists($path)) {
        echo 'Le fichier : "' . $path . '" existe';
    } else {
        echo 'Erreur, le fichier : "' . $path . '" n&apos;existe pas';
    }
     
    // découpage du fichier dans un array
    $lines0 = file($path);
     
    // Tableau qui contient les différents patterns de mes regEx
    $aPattern = array(
        '/(include|require){1}(_once)?[ ]?[\(]?[\'"](.*?)[\'"][\)]?[ ]?;/im',
        '/(_once){1}/im',
        '/(include){1}/im',
        '/(require){1}/im'
    );
     
    // Tableau qui contient les replace qui correspondent aux patterns 
    $aReplace = array(
        '${1}${2} ROOT . \'${3}'.'\';',
        '_once',
        'include',
        'require'
    );
    $max = count($aPattern);
     
    $i = 0;
    $j = 1;
    // Je fais une boucle par pattern
    while($i < $max) {
        ${'lines' . $j} = array();
        // puis une boucle par ligne de mon fichier
        foreach (${'lines' . $i} as ${'line' . $i}) {
            array_push(
                ${'lines' . $j},
                array(
                    preg_replace($aPattern[$i], $aReplace[$i], ${'line' . $i})
                )
            );
        }
        // pour vérifier j'affiche le résultat du traitement de chaque pattern
        echo '<br>VALEUR DU TRAITEMENT ' . $j .' : <br>';
        var_dump(${'lines' . $j});
        $i++;
        $j++;
    }
    Ce qui est étrange c'est que cette solution fonctionne pour 2 boucles, puis plante au début de la 3ème avec pour message : "( ! ) Notice: Array to string conversion in C:\wamp64\www\laboratoire\beforeCutting.php on line 63"
    La ligne 63 correspond à : preg_replace($aPattern[$i], $aReplace[$i], ${'line' . $i})

    Si ça fonctionne 2 fois pourquoi pas plus? Je ne vois pas trop le problème.
    C'est dommage parce que j'étais très fier de mes variables dynamiques.

    Vous avez une idée?

  14. #14
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 093
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 093
    Points : 6 754
    Points
    6 754
    Par défaut
    Ah oui les variables dynamiques, on est toujours fier de les placer. Et puis on s’absente quinze jours, et au retour on percute plus rien à ce qu’on a codé

    La clarté du code est plus importante qu’un éphémère sentiment de fierté. Moi par exemple, tu as réussi à m’embrouiller : il a fallu que je m’accroche pour comprendre quels noms de variables réels étaient utilisés in fine dans le script, et aussi réaliser que tu n’avais pas tout à fait compris comment on utilise preg_replace. Confer la doc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
    mixed est un mot-clé de la doc qui signifie « un mélange de plusieurs types ». Il faut lire ce qui est en-dessous pour connaître les détails. En l’occurence, $pattern et $replacement peuvent être des tableaux, auquel cas la fonction détecte que ce sont des tableaux et les parcourt automatiquement, tu n’as donc pas besoin de faire une boucle.

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    echo preg_replace([ '/a/', '/b/' ], [ 'X', 'Y' ], 'abcabcabc');
    D’autre part, j’ai un début d’explication sur pourquoi ça marche les deux premières fois mais pas après. À partir du 3e traitement, tes tableaux ont plusieurs dimensions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      0 => 
        array (size=1)
          0 => 
            array (size=1)
              0 => string 'Array' (length=5)
    On voit des chaînes 'Array' qui sont le résultat d’une conversion de tableau en chaîne. Ce sont ces conversions qui génèrent les messages notice que tu as vus.

    Je pense que le coupable est ce array que tu mets autour de ton preg_replace à la ligne 62.

    Pour résumer, laisse preg_match s’occuper des tableaux de patterns et de remplacements, elle fait ça très bien toute seule.

    La doc nous dit aussi que $subject peut être un tableau. Puisque tes chaînes à traiter sont déjà dans un tableau, preg_match peut itérer dessus également. Au final, tu n’as aucune boucle à écrire !

    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
    21
    22
    23
    24
    25
    ...
     
    // découpage du fichier dans un array
    $lines0 = file($path);
     
    // Tableau qui contient les différents patterns de mes regEx
    $aPattern = array(
        '/(include|require){1}(_once)?[ ]?[\(]?[\'"](.*?)[\'"][\)]?[ ]?;/im',
        '/(_once){1}/im',
        '/(include){1}/im',
        '/(require){1}/im'
    );
     
    // Tableau qui contient les replace qui correspondent aux patterns
    $aReplace = array(
        '${1}${2} ROOT . \'${3}'.'\';',
        '_once',
        'include',
        'require'
    );
     
     
    var_dump(
      preg_replace($aPattern, $aReplace, $lines0)
    );
    Au fait, quelques suggestions à propos de tes patterns.
    • Tu peux virer les {1}, ils ne servent à rien. Une correspondance est reconnue une seule fois de base.
    • Les [ ]? sont des classes à un seul caractère, l’espace. Tu peux les remplacer par ?, ou \s? pour plus de clarté. Note que PHP autorise plusieurs espaces à la suite, donc \s* à la place de \s? rendrait ton pattern plus robuste.
    • De la même façon, tu peux retirer les crochets autour de \( et \).
    • Le drapeau /m ne change rien quand tu n’utilises pas les ancres ^ et $ ; de plus, ton fichier est déjà découpé en lignes par la fonction file.
    • Tu peux utiliser une référence arrière pour faire correspondre le type de guillemet : '/([\'"])(.*?)\1/'. Pour ça, attention aux groupes capturants. Chaque paire de parenthèses constitue un groupe capturant, et les références sont comptées en prenant la parenthèse ouvrante. Si tu ne veux pas qu’un groupe soit capturant, il faut écrire (?: ... ).
    • Pour finir, tes trois derniers patterns ne font rien que le premier ne fait déjà, donc tu peux les supprimer.

    Au final, voici à quoi ta regex pourrait ressembler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    '/((?:include|require)(?:_once)?)\s*\(?([\'"])(.*?)\2\)?\s*;/i',
      (             1               )      (  2  )( 3 )
    J’ai indiqué les groupes capturants en-dessous avec leurs numéros de référence. Cette regex te renverra par exemple INCLUDE_ONCE en groupe 1, que tu pourras traiter avec strtolower ou mb_strtolower ; le guillemet en groupe 2 ; et le chemin du fichier en groupe 3.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  15. #15
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Tu te compliques la vie (et le code) en découpant ton fichier en lignes...

    Citation Envoyé par mathieu Voir le message
    Si vous voulez lire le fichier en entier et le réécrire d'un coup je vous conseille de plutot utiliser ces fonctions :
    http://php.net/file_get_contents
    http://php.net/file_put_contents
    Quant à tes array pattern / replace :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            $file_content_clean = preg_replace($aPattern, $aReplace, $file_content);
    C'est quand même plus simple et clair, non ?
    Dernière modification par Invité ; 16/11/2017 à 08h24.

  16. #16
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    Bonjour à tous,

    J'ai lu attentivement (enfin je l'espère) ce que vous m'avez dit et j'ai essayé de le mettre en pratique. J'utilise maintenant file_get_contents() et je réécris mon résultat dans un autre fichier. J'ai également affiné ma RegEx suite à vos conseils communs.

    C'est en effet plus simple et plus propre même s'il reste encore quelques détails à perfectionner.

    J'aimerais savoir s'il est possible (et comment surtout parce que j'ai fait des tests mais rien ne donne de résultats concluants) de faire un traitement sur un groupe capturant pendant le preg_replace() ?

    Voici mon code:
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    // Racine du source
    define('ROOT', __DIR__ . DIRECTORY_SEPARATOR);
    // Dossier source
    $folder = 'ressources' . DIRECTORY_SEPARATOR;
    // Fichier source
    $file = 'testFile.php';
    // Chemin complet de mon fichier source
    $path = ROOT . $folder . $file;
     
    // Teste si le fichier existe
    if (file_exists($path)) {
        echo 'Le fichier : "' . $path . '" existe';
    } else {
        echo 'Erreur, le fichier : "' . $path . '" n&apos;existe pas';
    }
     
    // Le contenu du fichier est mis en variable
    $fileContent = file_get_contents($path);
     
    // Pattern pour la RegEx
    $aPattern = '/((?:include|require)(?:_once)?)\s*\(?(?:[\'"])(.*?)(?:[\'"])[\)]?\s*[;]/i';
     
    // Replace qui correspond à mon pattern
    $aReplace = '${1} ROOT . \'${2}'.'\';';
     
    // J'effectue mon traitement de RegEx
     $fileContentClean = preg_replace($aPattern, $aReplace, $fileContent);
     
    // Déclaration de mon fichier cible
    $cleanFile = 'clean.php';
     
    // Chemin complet du fichier cible
    $newPath = ROOT . $folder . $cleanFile;
     
    // Ouverture du fichier cible
    $f = fopen($newPath, 'r+');
     
    // Ecriture dans le fichier cible
    fwrite($f, $fileContentClean);
     
    // Fermeture du fichier cible
    fclose($f);
    Pour finir donc je voudrais faire un strtolower() sur mon groupe capturant ${1}. J'ai voulu faire quelque chose dans le genre :
    $aReplace = strtolower(${1}) ROOT . \'${2}'.'\';';

    Mais cela provoque des erreurs. Est-ce possible et comment procéder?

    Merci à vous pour vos conseils, je crois que je n'aurais jamais réussi seul à faire quelque chose de potable.

  17. #17
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Pourquoi t'acharnes-tu à mettre des accolades là où elles ne sont pas utiles ??

    Relis la doc :



    replacement
    [...]
    replacement peut contenir des références de la forme \\n ou, (depuis PHP 4.0.4) $n. Cette dernière forme est recommandée.
    [...]
    Lorsque vous travaillez avec un masque de remplacement où une référence arrière est directement suivie par un nombre [...]
    Dans ce cas, la solution est d'utiliser la syntaxe \${1}1. Cela créera une référence arrière isolée $1, suivi du nombre littéral 1.

  18. #18
    Invité
    Invité(e)
    Par défaut
    Pour ta problématique, Watilin t'avais mis sur la bonne piste.

    Citation Envoyé par Watilin Voir le message
    Pour plus de souplesse on peut utiliser preg_replace_callback, c’est une ruse de Sioux...

    après essai(s), j'arrive à :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Pattern pour la RegEx
    $aPattern = '/((?:include|require)(?:_once)?)\s*\(?(?:[\'"])(.*?)(?:[\'"])[\)]?\s*[;]/i';
     
    // J'effectue mon traitement de RegEx
    $fileContentClean = preg_replace_callback($aPattern, 
    	function ($matches) {
    		return strtolower($matches[1]).' ROOT . \''.$matches[2].''.'\';';
    	},
    	$fileContent);

  19. #19
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 093
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 093
    Points : 6 754
    Points
    6 754
    Par défaut
    Merci jreaux62.

    General_Batton, je voudrais reformuler de façon plus claire ce que j’avais déjà dit à propos de ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $aPattern = ' ... [;]/i';
    Les crochets autour d’un seul caractère sont inutiles. Voir cet exemple. D’après les quelques tests que j’ai fait, ça ne change rien aux performances, mais dans la mesure où ils rendent la regex moins lisible, il vaut mieux ne pas les mettre
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  20. #20
    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
    Merci de ta confiance jreaux62!

    À propos des détails d'implémentation:

    PCRE ne s'occupe pas des remplacements (du moins jusqu'à sa version 8.41 qui équipe PHP 7.2rc6, mais une fonction de remplacement est fournie avec PCRE 10.0 (PCRE2)), il se contente de trouver des correspondances et de fournir les résultats, à la charge ensuite de chaque langage de les exploiter et de fournir sa propre fonction de remplacement. Les commandes \u \l \U \L ne sont donc pas fournies par la bibliothèque PCRE(*) et n'existent pas non plus en PHP.
    Elles sont toutefois assez répandues. C'est, je pense, dû en grande partie à la bibliothèque Boost qui les propose (on peut le vérifier avec notepad++ ou sublimetext qui sont basés dessus). Elles proviennent du langage Perl qui les a probablement reprises de l'utilitaire sed; mais même en Perl, elles ne sont pas liées au moteur de regex lui-même, mais à l'implémentation des chaînes de caractères en Perl. Sans mettre en jeu la moindre regex, on peut écrire en ligne de commande:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ perl -E'say "\upim \Upam\E P\LOU\EM";'
    Pim PAM PouM
    Rien d'étonnant à ce qu'un utilitaire comme regex101 les propose et n'importe quel langage pourrait choisir de les implémenter pour ses chaînes de remplacement.

    (*) Pour lever toute ambiguïté, le point 5 de la rubrique des différences avec Perl dans la documentation de PCRE, aborde le sujet de ces séquences d'échappement, mais uniquement au sein d'une pattern, pas au sein d'une chaîne de remplacement.

    Même chose pour le modificateur g qu'on ne retrouve pas en PHP. Là encore, c'est un choix d'implémentation. PHP a choisi de proposer deux fonctions différentes preg_match et preg_match_all toutes deux pourtant basées sur une même fonction. La raison sous-jacente est probablement liée au choix du format du résultat pour ces deux fonctions:
    • Pour preg_match: un tableau simple ou un tableau bidimensionnel quand l'option PREG_OFFSET_CAPTURE est activée.
    • Pour preg_match_all: un tableau bidimensionnel ou tridimensionnel quand l'option PREG_OFFSET_CAPTURE est activée, le tout avec deux dispositions possibles via les options PREG_PATTERN_ORDER et PREG_SET_ORDER


    Soit en tout six formats de résultat différents. Déjà qu'on se perd facilement avec ça, je n'imagine même pas ce que ce serait avec une seule fonction et le modificateur g.

    Quant aux fonctions de remplacement et à celle de split, elles sont globales par défaut mais disposent d'un paramètre pour limiter le nombre de résultat.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

Discussions similaires

  1. Faire tourner une image sur son axe
    Par choupinou22 dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 04/07/2015, 17h49
  2. Faire tourner une appli XP sur W7
    Par pierrot67 dans le forum Débuter
    Réponses: 4
    Dernier message: 07/09/2012, 13h28
  3. Réponses: 7
    Dernier message: 15/07/2011, 05h35
  4. Faire tourner une forme sur elle-même
    Par Suditidus dans le forum ActionScript 3
    Réponses: 1
    Dernier message: 14/06/2010, 11h05

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