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 :

preg_replace: plantage étrange avec l'option 's' sur longue chaine [RegEx]


Sujet :

Langage PHP

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut preg_replace: plantage étrange avec l'option 's' sur longue chaine
    Bonsoir,

    PHP Version 5.2.14

    je viens de passer la soirée sur un bug étrange. J'ai tenté d'isoler le problème dans le code épuré suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    <?php
    $texte = '[lien NumLien=1]sfds[/lien]
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll';
     
    echo preg_replace('#\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#s', 'bonjour',$texte);
    ?>
    EDITION: j'ai remplacé le replace_callback par un replace car, après vérification, ils se trouve qu'elles se comportent exactement de la même façon (mais replace a l'avantage de ne pas attirer l'attention sur une fonction anonyme dans la résolution du problème).

    Si tout fonctionne on devrait voir apparaître la chaîne inintelligible sur la page. Or la page est blanche, ce qui indique que preg_replace_callback a planté, ne renvoyant pas de texte.

    MAIS j'ai trouvé 4 cas dans lesquels ça fonctionne à nouveau:

    - on enlève l'option s.

    - on réduit le nombre de caractères en supprimant une des lignes de la chaîne.

    - on enlève la première ligne, elle qui colle à l'expression régulière (y compris si on la remplace par un nombre équivalant ou supérieur de caractères.

    - on enlève de l'expression régulière par exemple le paramètre '(.*)' du milieu, qui se trouve juste avant '(?: AfficheClics...', ou bien son petit frère juste avant le crochet fermant échappé.

    Qu'en pensez-vous?

  2. #2
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Bonjour,


    Je ne comprends pas ce qu’est censé faire ton code.

    Qu’est ce que tu appelles la chaîne inintelligible ?
    ’sfds’ ?
    Car ta RE, se terminant par [/lien\] , le résultat ne peut dépendre en rien de ce qui se trouve au delà de '[/lien]' dans la chaîne $texte.

    Je pense d’autre part qu’il faut un ’return quelque chose’ dans le code de create_function et non pas simplement ''

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Bien sûr le code original contient des instructions dans le create_function mais que celles-ci soient présentes ou non ne changeait rien au bug, c'est pourquoi je les ai enlevées (si du texte correspond à l'expression régulière il est dès lors remplacé par... rien, il est tout simplement supprimé). Bien sûr également le résultat ne peut dépendre ce qui se trouve au delà de [/lien] et c'est bien ça qui est étrange. D'autant plus que le problème n'est pas que le résultat est faux, mais qu'il n'y a pas de résultat, aucun texte, n'est renvoyé par preg_replace_callback.
    Ce que j'appelle chaîne inintelligible est l'ensemble de la chaîne $texte, remplie de caractères au hasard à part pour la première ligne.

    Ce code est réduit au minimum utile à la démonstration qu'il plante avec ma version de PHP, et qu'il ne plante plus au moins quand on lui applique une de mes 4 modifications présentées dans mon précédent message. À savoir: on enlève l'option s, on en lève une ligne de la chaine,...

    Est-ce que quelqu'un ayant la même versiond de php (ou même une autre) reproduit le même plantage?


    EDITION: j'ai remplacé le replace_callback par un replace car, après vérification, ils se trouve qu'elles se comportent exactement de la même façon (mais replace a l'avantage de ne pas attirer l'attention sur une fonction anonyme dans la résolution du problème).

  4. #4
    Membre habitué Avatar de Rapha222
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2007
    Messages : 128
    Points : 168
    Points
    168
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Je pense d’autre part qu’il faut un ’return quelque chose’ dans le code de create_function et non pas simplement ''
    +1, tu t'es trompé dans l'utilisation du Callback :

    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
     
    [rapha@desktop Bureau]$ cat test.php
    <?php                                                                                                               
    $texte = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.                                                  
    Maecenas lectus felis, rhoncus a pretium ut, iaculis at mi.                                                         
    Curabitur mollis pellentesque purus, eget tristique dolor cursus at.                                                
    Nulla mattis consequat eros a cond [lien]sfds[/lien] lorem ipsum.                                                   
    Fusce quis tortor leo, eget consequat purus.
    Nam et magna sed ante luctus porttitor vel ut lectus.
    Ut in dui ut nunc varius adipiscing.
    ';
     
    echo preg_replace_callback('#\[lien\](.*)\[/lien\]#',
                               create_function('$param',
                                    'return "LIEN";'),
                               $texte);
    ?>
     
    [rapha@desktop Bureau]$ php test.php
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Maecenas lectus felis, rhoncus a pretium ut, iaculis at mi.
    Curabitur mollis pellentesque purus, eget tristique dolor cursus at.
    Nulla mattis consequat eros a cond LIEN lorem ipsum.
    Fusce quis tortor leo, eget consequat purus.
    Nam et magna sed ante luctus porttitor vel ut lectus.
    Ut in dui ut nunc varius adipiscing.
    Fedora 12 x64 (laptop) - OpenSuSe 11.2 (desktop)
    Hébergeur d'images et de fichiers (< 75Mio) gratuit et sans pub

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par Florimond Voir le message
    EDITION: j'ai remplacé le replace_callback par un replace car, après vérification, ils se trouve qu'elles se comportent exactement de la même façon (mais replace a l'avantage de ne pas attirer l'attention sur une fonction anonyme dans la résolution du problème).
    Donc, Raphael, as-tu fais le test comme moi sans rien dans la fonction, et puis avec ton return "LIEN", pour démontrer que c'est bien ça qui ne fonctionne pas?

    De plus je crois avoir montré que c'était précisément ma regex, telle quelle qui faisait planter la fonction (replace ou replacecallback), donc ton test est doublement inutile. Peux-tu recommencer avec ma regex ET la même quantité de texte ET un texte comprenant un morceau qui match à l'expression régulière. Puis si ça ne fonctionne pas, enlever le texte qui match, ou une ligne du texte au hasard, ou l'option 's' etc..

    Enfin possède-tu la même version de php que moi?

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Avec php version 5.3.2-1, même problème.

    Par contre le code Perl équivalant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $texte = '[lien NumLien=1]sfds[/lien]
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll';
     
    $texte =~ s#\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#bonjour#s;
     
    print $texte;
    fonctionne parfaitement comme attendu, y compris si mon

    [lien(...)]blabla
    blabla[/lien]

    est étalé sur plusieurs lignes. Perl V5.10.1

  7. #7
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    1)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $texte = '[lien NumLien=1]sfds[/lien]
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll';
    À quoi cela peut-il bien servir de faire suivre 40 ’ù’ puis 21fois ’k’ puis 51 fois ’l’
    Qu’est ce que ça apporte ?



    2)

    Ce que j'appelle chaîne inintelligible est l'ensemble de la chaîne $texte, remplie de caractères au hasard à part pour la première ligne.
    Ce n’est pas clair à cause de l’ambigüité de ce à quoi se rapporte « à part pour la première ligne »

    La phrase signifie-t-elle:

    - que la première ligne n’est pas remplie de caractères au hasard ?

    - ou que la première ligne est exclue de ce que tu appelles “chaîne inintelligible“ ?

    Pourrais tu répondre, s’il te plait, en donnant explicitement la chaîne contenue dans $texte, que tu considères comme inintelligible ? Merci.

    L’aide que l’on peut t’apporter passe obligatoirement par la compréhension de ce que tu appelles “chaîne inintelligible“ puisque son apparition en tant que résultat constitue la définition de la réussite du programme voulu:

    Citation Envoyé par Florimond Voir le message
    Si tout fonctionne on devrait voir apparaître la chaîne inintelligible sur la page.



    3)

    eyquem
    Je pense d’autre part qu’il faut un ’return quelque chose’ dans le code de create_function et non pas simplement ''
    Florimond
    Bien sûr le code original contient des instructions dans le create_function mais que celles-ci soient présentes ou non ne changeait rien au bug, c'est pourquoi je les ai enlevées (si du texte correspond à l'expression régulière il est dès lors remplacé par... rien, il est tout simplement supprimé).
    Il serait mieux de nous dire quelles sortes d’instructions étaient présentes avant que tu trouves inutile de les garder. Cela nous permettrait de savoir si ces instructions que tu as décidé d’enlever comportaient un return ou non.

    Car ta réponse n’en est pas une sur ce point précis, alors que c’est celui qui m’a paru le plus immédiatement en cause.
    Ce que tu apportes par rapport à ton premier post, et l’appui de Rapha222, me poussent à considérer qu’il ne faut pas laisser tomber si rapidement cette piste.

    En effet, d'apres
    Citation Envoyé par Florimond #3 Voir le message
    (si du texte correspond à l'expression régulière....
    on peut légitimement en déduire que tu as vérifié que l’expression régulière capte bien quelque chose.
    Est-ce bien ce que tu voulais ? Il faut le préciser.

    Mais
    a-
    Citation Envoyé par Florimond #3 Voir le message
    (si du texte correspond à l'expression régulière il est dès lors remplacé par... rien, il est tout simplement supprimé)
    l'expression réguliere n'étant pas en cause, c’est bien que c'est preg_replace_callback qui foire, non ?

    D'ailleurs , tu l'as écrit toi meme des le début:
    b-
    Citation Envoyé par Florimond #1 Voir le message
    Or la page est blanche, ce qui indique que preg_replace_callback a planté, ne renvoyant pas de texte.
    On ne comprend soit dit en passant plus rien quand on lit ensuite:
    Citation Envoyé par Florimond #5 Voir le message
    De plus je crois avoir montré que c'était précisément ma regex, telle quelle qui faisait planter la fonction (replace ou replacecallback),

    -------------------------------

    Or pour moi y a pas 36 possibilités pour que preg_replace_callback() foire. Vue la simplicité de ses arguments, c'est que c'est create_function() qui la fait foirer.



    Donc , en continuant sur mon idée, j'ai trouvé:

    string create_function ( string $args , string $code )

    Valeurs de retour

    Retourne un nom de fonction unique, sous la forme d'une chaîne de caractères, ou FALSE si une erreur survient.

    http://www.php.net/manual/fr/functio...e-function.php

    mixed preg_replace_callback ( mixed $pattern , callback $callback , mixed $subject [, int $limit = -1 [, int &$count ]] )

    Valeurs de retour

    preg_replace_callback() retourne un tableau si le paramètre subject est un tableau, ou, sinon, une chaîne de caractères. Si une erreur survient, la valeur retournée sera NULL.

    http://www.php.net/manual/fr/functio...e-callback.php
    Pour moi, l’absence de return dans la create_function() du premier post original fait qu’elle renvoie False, ce qui est cause que preg_replace_callback() renvoit Null.
    La page blanche qui s’affiche, c’est donc Null.



    4)

    Ce n’est pas une bonne chose de faire un EDIT dans le premier post, en changeant autant de choses que
    preg_replace_callback() par preg_replace()
    et
    '' par ’bonjour’.

    Il aurait fallu commencer par nous dire si de spécifier ’bonjour’ à la place de '' donnait un résultat différent avec le premier code comportant preg_replace_callback().

    Mais maintenant cela est devenu d’une grande confusion, on se perd dans ce à quoi se rapportent les réponses antérieures au changement et à quelles conditions d’exécution se rapportent les résultats.





    5)

    Par contre le code Perl équivalent
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $texte = '[lien NumLien=1]sfds[/lien]
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll
    camùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùklkkkkkkkkkkkkkkkkkkkkkjjhklllllllllllllllllllllllllllllllllllllllllllllllllll';
     
    $texte =~ s#\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#bonjour#s;
     
    print $texte;
    fonctionne parfaitement comme attendu, y compris si mon
    [lien(...)]blabla
    blabla
    [/lien]
    est étalé sur plusieurs lignes.
    Sauf que dans l’exemple , ’camùùùùùùùùùùùùùùùùùùùùù.....’ n’est pas du blabla blalbla compris entre [lien] et [/lien] puisqu’il est après.

    C’est une pagaille ton truc.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Ok ok. Je vais tâcher de reprendre mon expérience étape par étape, une chose à la fois, en laissant de côté toute formulation rhétorique, tout détail qui pourrait troubler inutilement l'attention, toute formulation orientée par le désir d'une réponse choisie à l'avance,... en étant plus clair, plus précis. À vous de me dire si j'y réussi.

    Note: Je travaille à présent avec php 5.3.3

    1) Mon problème:

    remplacer: "ceci est un texte quelconque qui précède le lien et je peux être très long [lien var1='bonjour' var2='salut' NumLien=1 var3=5 AfficheClics=0 var4='hello']je suis le lien[/lien] ceci est du texte qui suit le lien et je peux être très long également"

    (NumLien et AfficheClics étant des variables qui vont me permettre de 'fabriquer' le lien et ensuite disparaître de la chaine finale; les autres variables étant des variables quelconques, propres à la balises <a > et qui doivent s'y retrouver à la fin du traîtement)

    par: "ceci est un texte quelconque qui précède le lien et je peux être très long <a href var1='bonjour' var2='salut' var3=5 var4='hello' href="URL retrouvée dans la BDD">je suis le lien</a> ceci est du texte qui suit le lien et je peux être très long également"

    2) Élaboration d'une solution

    Avant de m'occuper du côté recherche dans la bdd et remplacement par les données trouvées, il faut que je cherche à reconnaître la 'déclaration' d'un lien au milieu du texte.
    Pour ce faire, j'élabore l'expression régulière suivante:

    #\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#s

    On y retrouve mes deux paramètres utiles à la fabrication du lien (NumLien et AfficheClics), entrecoupés de (.*) destinés à récupérer toute variable supplémentaire qui serait destinée à la balise <a >. Le texte se trouvant entre <a> et </a> pouvant être n'importe quoi, c'est encore une fois un (.*) que je place dans mon expression régulière entre [lien (paramètres)] et [/lien].

    3) Passons aux tests

    Maintenant, je vais tester mon expression régulière. Pour ce faire je décide d'utiliser la fonction preg_replace(). Si l'expression désignée par ma regex est trouvée, mettons pour l'expérience que nous la remplaçons par un 'OK'.

    Premier test

    Cas simple...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <?php
    	$texte = "[lien NumLien=1]Lipsum[/lien]";
    	echo preg_replace('#\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#s', 'OK', $texte);
    ?>
    Résultat: un simple 'OK' s'affiche, l'expression a donc été trouvée et remplacée.

    Second test

    On reprend la chaine précédente mais on ajoute une phrase avant, et une phrase après...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <?php
    	$texte = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean luctus, elit ac pulvinar scelerisque, enim dui fermentum purus, pretium consectetur sapien nunc quis arcu. [lien NumLien=1]Lipsum[/lien] Aliquam erat volutpat. Sed luctus, est sit amet cursus hendrerit, augue lectus dapibus augue, sit amet condimentum quam velit eget arcu.";
     
    	echo preg_replace('#\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#s', 'OK', $texte);
    ?>
    Résultat: les deux phrases latines s'affichent à l'écran, entre elles deux on retrouve notre "OK". Pour l'instant tout se passe bien.

    Troisième test

    On reprend la chaine précédente, mais on lui ajoute à la fin tout un paragraphe...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <?php
    	$texte = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean luctus, elit ac pulvinar scelerisque, enim dui fermentum purus, pretium consectetur sapien nunc quis arcu. [lien NumLien=1]Lipsum[/lien] Aliquam erat volutpat. Sed luctus, est sit amet cursus hendrerit, augue lectus dapibus augue, sit amet condimentum quam velit eget arcu. Curabitur adipiscing laoreet lacus sollicitudin elementum. Aliquam a congue massa. Nunc eget auctor neque. Aliquam scelerisque condimentum porta. Nulla facilisi. Integer eleifend, orci vel volutpat volutpat, tellus erat sodales dui, nec placerat dolor nisl ac leo. Cras malesuada scelerisque vehicula. Etiam tincidunt fringilla auctor. Integer rhoncus pellentesque turpis nec malesuada. Curabitur a mollis nibh. Phasellus sapien quam, malesuada quis fringilla vel, vestibulum non turpis. Donec in est leo. Morbi aliquet, ipsum eu condimentum euismod, turpis dolor mollis dolor, non mollis quam massa porttitor ipsum. Etiam tempor tincidunt libero, et suscipit eros lobortis vitae. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae ipsum massa. ";
     
    	echo preg_replace('#\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#s', 'OK', $texte);
    ?>
    Et là, c'est le drame, plus rien ne s'affiche. Pourtant nous n'avons fait qu'alonger le texte suivant le lien. Comment est-ce possible?

  9. #9
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Ah, cette fois , c’est fort bien , on s’y retrouve.





    Il faut que je te précise que je connais à peine PHP.
    Par contre j’aime bien les problèmes de regex et il m’arrive de donner un coup de main sur d’autres forum que celui du langage que j’utilise , parce qu’au niveau des regex seules c’est tout à fait possible de le faire, et parce qu’il y a plus souvent de tels problèmes posés sur le forum Perl ou PHP que sur le forum de “mon“ langage.

    Mais si des problèmes impliquent des propriétés de PHP même et une connaissance sérieuse de PHP, je suis incompétent.

    De plus, je ne peux pas tester des codes PHP, car j’ai enlevé WAMP qui encombrait ma mémoire sans marcher correctement.





    Ceci dit, pour ce qui est de ce que tu décris, je suis interloqué.


    On reprend la chaine précédente, mais on lui ajoute à la fin tout un paragraphe...
    Et là, c'est le drame, plus rien ne s'affiche. Pourtant nous n'avons fait qu'alonger le texte suivant le lien.

    Comment est-ce possible?
    Je ne sais pas.

    Je peux simplement te dire que l’essai de tes trois codes avec un autre langage me donne 3 fois le bon résultat.

    Je n’ai pas de piste pour chercher, car ta RE me semble correcte et la variabilité de la détection en fonction d’une portion de texte qui n’est pas concernée par la regex est pour moi une aberration.



    Seule idée que j’ai:

    tester de façon répétée le code avec la grande longueur de texte final qui fait foirer,
    mais en enlevant à chaque fois un caractère, pour voir à partir de quelle longueur ça se remet à marcher.
    On aura ainsi une idée de l’endroit où porter notre attention.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Merci pour ta réponse.

    On est donc bien d'accord que c'est fort étrange. Comme le j'ai dit précédemment, j'ai moi aussi fait l'expérience dans un autre langage... et en Perl elle semble être toujours un succès. Par curiosité, pourrais-je savoir dans quel langage tu as fait les test?

    Pour ce qui est de l'expérience que tu me proposes je l'ai faite hier soir. Je ne peux pas te dire quel fut le compte, mais je sais (parce que c'est ce que je cherchais) que ce n'était ni un nombre proche de 127, ni 255, ni encore 511 (ou ma mémoire est vraiment mauvaise). Mais je ne pense pas que cette piste va nous amener bien loin.

    Finalement il semble donc que mon expression régulière soit bonne, le code est assez basique, penses-tu qu'il faille envisager un bug dans l'implémentation de la fonction elle-même? Raphaël quant à lui semble avoir fait des expériences similaires, obtenu les mêmes problèmes, mais en concluant qu'il devait y avoir une erreur dans mon expression régulière... sans pour autant arriver à m'en proposer une meilleure version...

    Et ce qui m'inquiète le plus c'est que, avec la version de PHP de mon hébergeur, je peux me passer de l'option s et ça se met à fonctionner. Mais ça ne "résout" plus le problème avec la version 5.3.3 (que je viens d'installer sur ma machine), donc il faudra tôt ou tard trouver une solution...

  11. #11
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    C’est étrange, comment tu procèdes.

    en Perl elle semble être toujours un succès
    Pourquoi « semble » ?
    Il faut établir des choses avec certitude, c’est du moins la démarche que je préfère à celle qui consiste à faire des trucs et quand ça marche on se dit “ouf“, et on continue comme ça en pataugeant dans des trucs vagues... jusqu’au prochain problème



    De même:
    Je ne peux pas te dire quel fut le compte
    Ah bon.... Je pensais qu’il serait facile et rapide de déterminer ça avec précision.
    C’est à dire que, par exemple, à 500 caractères après [/lien] ça marche et à 501 ça ne marche plus.

    Il suffit de raccourcir le texte à partir de la fin de une lettre à chaque essai. je ne vois pas où est la difficulté. On peut faire ça soit à la main;
    soit avec un programme: à quoi sert de savoir programmer, sinon ?

    Et quand je lis ça:
    (ou ma mémoire est vraiment mauvaise).
    je ne peux que rappeler ce que j’ai écrit à l’instant sur les choses vagues.

    En fait ça n’a pas l’air de t’intéresser de creuser dans une voie, et je fais le rapprochement:
    Citation Envoyé par Florimond #10 Voir le message
    Mais je ne pense pas que cette piste va nous amener bien loin.
    Citation Envoyé par Florimond #8 Voir le message
    orientée par le désir d'une réponse choisie à l'avance

    Pour ma part je viens de compter.

    Dans ton second test,
    Aliquam erat volutpat. Sed luctus, est sit amet cursus hendrerit, augue lectus dapibus augue, sit amet condimentum quam velit eget arcu."
    comporte 137 caractères,

    Dans ton troisième test
    " Aliquam erat volutpat. Sed luctus, est sit amet cursus hendrerit, augue lectus dapibus augue, sit amet condimentum quam velit eget arcu. Curabitur adipiscing laoreet lacus sollicitudin elementum. Aliquam a congue massa. Nunc eget auctor neque. Aliquam scelerisque condimentum porta. Nulla facilisi. Integer eleifend, orci vel volutpat volutpat, tellus erat sodales dui, nec placerat dolor nisl ac leo. Cras malesuada scelerisque vehicula. Etiam tincidunt fringilla auctor. Integer rhoncus pellentesque turpis nec malesuada. Curabitur a mollis nibh. Phasellus sapien quam, malesuada quis fringilla vel, vestibulum non turpis. Donec in est leo. Morbi aliquet, ipsum eu condimentum euismod, turpis dolor mollis dolor, non mollis quam massa porttitor ipsum. Etiam tempor tincidunt libero, et suscipit eros lobortis vitae. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae ipsum massa. "
    en comporte 901.

    Inutile donc de chercher si le basculement “ça marche/ça ne marche plus“ pouvait être autour de 127.
    Quant à 255 et 511, ça dépend de ce qu’on appelle “proche de“, mais comme le basculement est nécessairemnt entre 137 et 901, il y a une certaine probabilité que l’un des deux nombres 255 et 511 n’en soit pas si éloigné que ça.



    Je vais réinstaller WAMP et j’espère que j’arriverai à faire tourner des programmes. La précédente fois , j’avais un problème, et personne ne m’avait répondu quand j’avais demandé un coup de main.
    À mon avis, je n’obtiendrai pas ton résultat sur le troisième test. Il y a un grain de sable ailleurs que dans tes codes, je ne crois pas que ce soit les codes tels que tu les as donnés soient buggés.





    Finalement il semble donc que mon expression régulière soit bonne
    Tant qu’il y aura un « semble » quelque part, je me garderai d’éliminer une piste.
    Je me dis plutôt: que faudrait-il faire pour consclure avec certitude si la RE est correcte ou non ?





    penses-tu qu'il faille envisager un bug dans l'implémentation de la fonction elle-même?
    Je n’en sais rien. Je ne suis pas un spécialiste de PHP. J’ai l’impression que je rencontre souvent cette hypothése émise sur les forums PHP; à quoi est-ce dû ? je n’en sais rien. Mais je pense qu’avant d’arriver à une telle hypothèse , il faut avoir vraiment cherché beaucoup. Car étant donné le temps depuis lequel existent les fonctions PHP et le nombre énorme de gens qui les ont utilisées, je pense qu’on peut quand même faire crédit à PHP de disposer de fonctions correctement implémentées. Le contraire serait navrant.





    Raphaël quant à lui semble avoir fait des expériences similaires, obtenu les mêmes problèmes, mais en concluant qu'il devait y avoir une erreur dans mon expression régulière
    Rapha222 n’a pas fait DES expériences. Il a fait tourner UN code avec un return dans la fonction create_function() , une chaîne de remplacement de longueur non nulle, et un texte soumis au remplacement simplifié.
    Il n’a obtenu aucun problème avec son code.
    Il n’a fait aucune conclusion. Il a émis l’avis que tu t’étais trompé dans l’expression de la callback.




    Enfin, il m’apparait qu’il faudrait quand même s’intéresser de près à la raison pour laquelle la présence ou l’absence de l’option s a une influence sur le résultat.

    Est-ce que les 3 tests que tu as donnés dans le message #8 ont été faits avec ’[lien]’ et ’[/lien]’ dans $texte ou bien avec de vrais liens ?

    Je me dis qu'il doit y avoir un retour à la ligne quelque part qui joue le trouble-fête.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Les mêmes tests fonctionnent parfaitement en Perl. Mais je préfère toujours être prudent plutôt que de lancer des affirmations, c'est tout.

    Je ne peux pas te dire quel fut le compte simplement parce que je ne l'ai pas retenu étant donné que ce nombre ne me semblait pas correspondre à un limite "classique" en informatique (127, 255,...). Il est évident que ce compte est réalisé facilement même à la main, par dichotomie.

    Ce que je veux dire c'est que ce nombre ne va pas nous être vraiment utile à moins de plonger dans le code de la fonction... ce qui est en fait une bonne idée... mais demande du temps et du courage, temps que je n'ai pas en ce moment.

    Qu'entends-tu par "un grain de sable ailleurs"? j'exécute ces codes tels que je les ai donnés, sans rien de plus. Ils plantent chaque fois, que ce soit sous linux avec php5.2.x et 5.3.1 ou sous Windows avec php5.3.3.

    Quant à Raphaël, je sais que ce n'est pas très "cool" pour ceux qui suivent le sujet, mais on en a parlé en messagerie instantanée, et c'est pour ça que je peux te dire qu'il a fait d'autres test...

  13. #13
    Membre émérite
    Avatar de Eric2a
    Homme Profil pro
    Technicien
    Inscrit en
    Septembre 2005
    Messages
    1 225
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Corse (Corse)

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 225
    Points : 2 411
    Points
    2 411
    Par défaut
    Salut,

    Citation Envoyé par eyquem
    étant donné le temps depuis lequel existent les fonctions PHP et le nombre énorme de gens qui les ont utilisées, je pense qu’on peut quand même faire crédit à PHP de disposer de fonctions correctement implémentées.
    +1

    Essaie avec cette expression légèrement modifiée :
    \[lien (.*?)NumLien=([0-9]+)(?: (.*?)AfficheClics=([01]))?(.*?)\](.*?)\[/lien\]
    Avec la fonction de callback
    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
     
    $str="...";
     
    // Fonction de callback
    function get_URL($matches){
    	$NumLien=$matches[2];
    	$AfficheClics=$matches[4];
    	$url='page.php?lien='.$NumLien.'&amp;Affclics='.$AfficheClics;
    	return '<a '.trim($matches[1]).' '.trim($matches[3]).' '.trim($matches[5]).' href="'.$url.'">'.trim($matches[6]).'</a>';
    }
     
    $str=preg_replace_callback(
    	'%\[lien (.*?)NumLien=([0-9]+)(?: (.*?)AfficheClics=([01]))?(.*?)\](.*?)\[/lien\]%si',
    	'get_URL',
    	$str
    );
    Sans fonction de callback
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    $str="...";
     
    $str=preg_replace(
    	'%\[lien (.*?)NumLien=([0-9]+)(?: (.*?)AfficheClics=([01]))?(.*?)\](.*?)\[/lien\]%si',
    	'<a \1\3\5 href="page.php?numlien=\2&amp;affclics=\4">\6</a>',
    	$str
    );

  14. #14
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Haaaaaaa!
    Je n'ai pas la possibilité de faire des tests approfondis ce soir, mais déjà je peux dire qu'en utilisant ta regex, le texte du 3eme test apparaît correctement, remplacé quand il le faut.

    Peux-tu m'expliquer ce qu'il se passe? À première vu ton ajout de '?' me semble tout à fait inutile et superflu, alors comment exactement dois-je comprendre cette expression?

    Mais bon, ça me chiffonnera quand même toujours... il restera quand même toujours ces aléas étranges des fonctions qui marchent dans certains cas avec ma regex, et puis plus du tout dans un autre, sans explication logique! Ou alors si tu l'as, explique moi... J'avais aussi la naïveté de penser que les regex PCRE seraient interprétées exactement de la même manière en Perl (qui fait logiquement autorité en la matière) et en php... je vois au cours de mes tests que c'est loin d'être le cas. Tout ça me semble assez mystérieux.

  15. #15
    Membre émérite
    Avatar de Eric2a
    Homme Profil pro
    Technicien
    Inscrit en
    Septembre 2005
    Messages
    1 225
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Corse (Corse)

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 225
    Points : 2 411
    Points
    2 411
    Par défaut
    Avec l'option s (PCRE_DOTALL), le métacaractère point (.) remplace n'importe quel caractère, y compris les nouvelles lignes.

    Il est intéressant de l'utiliser afin de prendre en compte les lignes construites comme dans l'exemple ci-dessous :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [lien NumLien=50 AfficheClics=0]
    	Le texte du lien
    [/lien]
    Mais il nous incombe d'inverser la tendance à la gourmandise en placant le point d'interrogation (?) après un quantificateur (+) ou (*) lui-même précédé du fameux méta-caractère (.).

    Concernant l'autre modification de l'expression :

    (?: (.*?)AfficheClics=([01]))?(.*?)\]
    Recherche...
    1. d'éventuels caractères effectivement suivis de "[i] AfficheClics=[0 ou 1]".
    2. d'autres caractères éventuels (avant le caratères ]).

    tandis que
    (.*)(?: AfficheClics=([01]))?(.*)\]
    Recherche...
    1. d'éventuels caractères éventuellement suivis de "[i] AfficheClics=[0 ou 1]".
    2. d'autres caractères éventuels (avant le caratères ]).

  16. #16
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Parfait! Merci beaucoup. En fait, je me suis rapidement initié aux expressions régulières il y a quelques jours, précisément pour faire ce remplacement de liens. Je vois que j'ai encore quelques lacunes puisque je ne connaissais pas cette possibilité de rendre un quantificateur non gourmand. Je m'étais bien posé une question similaire, mais je supposais qu'un quantificateur était toujours non gourmand.

    J'ai fait quelques tests un peu plus approfondis, pour comprendre que le problème majeur qui provoquait le plantage était bien d'avoir mis un (.*) devant une expression dont l'existence était facultative, puisque terminée par un '?', en plus d'un (.*) après cette expression facultative, de sorte que la fonction se perdait. Même si ma regex passe avec Perl, je vois bien qu'elle est plus correcte écrite comme vous l'avez fait (?: (.*?)AfficheClics=([01]))?(.*?), puisque, évidemment, on n'a besoin de récupérer "les caractères qui se trouvent avant AfficheClics" que s'il existe bel et bien un "AfficheClics" - et dans le cas ou AfficheClics est absent, les caractères éventuels sont de toutes façons récupérés par le (.*) suivant.

    Voilà, après les quantificateur non gourmands peut-être existe-t-il d'autres choses dont je n'ai encore pas idée, alors si tu connais un article qui me permettrait de parfaire ma formation, j'en veux bien le lien.

    Encore merci.

  17. #17
    Membre émérite
    Avatar de Eric2a
    Homme Profil pro
    Technicien
    Inscrit en
    Septembre 2005
    Messages
    1 225
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Corse (Corse)

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 225
    Points : 2 411
    Points
    2 411
    Par défaut
    Re,
    Citation Envoyé par Florimond
    si tu connais un article qui me permettrait de parfaire ma formation...
    Voici un lien qui devrait te satisfaire pleinenement...
    Les expressions rationnelles PCRE
    Un bon tutoriel qui inclus un testeur
    Citation Envoyé par Florimond
    remplacer le (.*?) par une classe négative ([^\]])
    Il suffit juste de préserver le quantificateur (*).
    \[lien (.*?)NumLien=([0-9]+)(?: (.*?)AfficheClics=([01]))?([^\]]*)\]([^[]*)\[/lien\]

    Edit: Je ne me suis pas rendu compte que tu avais supprimé la question concernant les classes négatives...

  18. #18
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2010
    Messages : 18
    Points : 11
    Points
    11
    Par défaut
    Merci bien pour le lien!

    Ainsi que pour la réponse à ma question, désolé mais je me suis rendu compte juste après que c'était en fait tout simple.

  19. #19
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Citation Envoyé par Florimond #16 Voir le message
    J'ai fait quelques tests un peu plus approfondis, pour comprendre que le problème majeur qui provoquait le plantage était bien d'avoir mis un (.*) devant une expression dont l'existence était facultative, puisque terminée par un '?', en plus d'un (.*) après cette expression facultative, de sorte que la fonction se perdait.
    Je ne crois pas que la cause du problème soit là.

    Il est vrai, comme tu l’as bien saisi, que la succession de 3 éléments de RE estampillés "facultatif", dont deux sont des .* qui captent tout (hormis les fins de ligne), est une mauvaise chose. Cela traduit une mauvaise réflexion sur le déroulement de la recherche d’un motif dans une chaîne.
    Mais je ne crois pas du tout que le moteur de regex se perde à cause de ça.
    On se perd éventuellement, nous, dans la compréhension de ce que commande une telle portion de RE, mais le moteur de regex, lui, ne se perd pas.



    En s’efforçant de rester simple, toute RE un tant soit peu charpentée peut être considérée comme composée de REs élémentaires, celles-ci étant définies par deux choses:
    - prise isolément, une RE élémentaire est une RE fonctionnelle à part entière.
    - l’étendue d’une RE élémentaire ne peut être prolongée ni vers la droite ni vers la gauche dans la RE globale sans couper en deux et invalider une RE élémentaire voisine.
    Certaines RE élémentaires exprime un matching facultatif, d’autres un matching obligatif.

    Il est difficile de définir plus précisément ce qui peut être considéré comme une RE élémentaire sans devenir verbeux, mais la notion se perçoit aisément dans la pratique.

    Ainsi la RE suivante
    #\[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]#s
    peut se décomposer ainsi:

    \[lien (.*)NumLien=([0-9]+)(.*)(?: AfficheClics=([01]))?(.*)\](.*)\[/lien\]




    Pour une RE simple dans laquelle des RE élémentaires elles aussi simples se succèdent tranquillement, la simplicité d'organisation permet au moteur de regex de chercher à établir le matching de la RE globale en examinant les REs élémentaires l’une après l’autre, sans complication.

    Dans une RE à la structure plus complexe, par contre, le moteur de regex examine les REs élémentaires de façon séquentielle tant que ça marche ainsi, mais dès qu’il le faut à cause d’une perte du matching, il se met à examiner toutes les possibilités offertes, en procèdant par des essais-erreurs dans l’arbre des REs constitutives de la RE globale, en reculant éventuellement, aprés avoir rencontré une impasse au bout de l’examen de plusieurs REs élémentaires consécutives, pour reprendre sa recherche à partir d’une position de la chaîne déjà passée et repartir dans une autre voie logique. Il s’acharne ainsi jusqu’à ce qu’il trouve une solution convenable aux yeux de la regex qu’il est chargé de respecter (la première solution trouvée suffit) ou alors qu’il ait épuisé toutes les possibilités, auquel cas il y a échec du matching global.




    Je prends l’exemple simplifié suivant pour illustrer le cas qui nous occupe:

    la chaîne dans laquelle chercher:
    "[lien glolo NumLien=39 tabalou AfficheClics=1 tabala gytew]"

    avec la RE suivante
    \[lien (.*)NumLien=[0-9]+(.*)(?: AfficheClics=[01])?(.*)\]

    jj

    On peut y distinguer les REs élémentaires suivantes:
    \[lien (.*)NumLien=[0-9]+ (.*) (?: AfficheClics=[01])?(.*)\]

    Le premier groupe (.*) , devant Numlien, matche avec ’glolo ’ car NumLien=([0-9]+) exprime une portion qui DOIT être trouvée. C’est un ancrage de la RE. Sans ancrage dans une RE, il n’y a que des REs élémentaires facultatives, et la RE globale n’a plus de sens.

    L’ancrage suivant présent dans la RE est le \] terminal.

    Entre les deux, 3 REs élémentaires facultatives.
    Aussi, quand le moteur de recherche continue après avoir trouvé le match sur ’Numlien=39’, le point du second groupe (.*) matche successivement avec un blanc, puis chacun des caractères de ’tabalou’, puis un blanc.... puis ’A’, et ’f’, et ’f’ et ’i’.... : pourquoi ce point du second (.*) s’arrêterait-il en effet de matcher puisqu’il matche avec tout ?
    Donc le moteur de regex continue d’avancer en vérifiant que le point matche avec tous les caractères successivement, c’est à dire tous ceux de ’AfficheClics=1’, puis un blanc, puis les caractères de ’tabala gytew’... puis ’]’ en dernier.

    Oui le point du second groupe (.*), dans un premier essai, matche jusqu’au dernier caractère.

    Mais le moteur de regex doit vérifier que la feuille de route qu’on lui a donnée est vérifiée jusqu’au bout.
    Donc il considère ensuite (?: AfficheClics=([01]))? : bon c’est facultatif, hop ça ne pose pas de problème.
    Ensuite il y a le troisième groupe (.*). Ben l’étoile fait que c’est facultatif, ce troisième groupe peut ne rien capturer.

    Et ensuite... paf, problème: le moteur de regex doit au moins trouver un ’]’ pour matcher avec \] , or il est au bout, il n’y a plus de caractères après, il est arrivé dans une impasse logique.



    Donc à ce moment là, il va rebrousser chemin tant qu'il le faudra pour trouver une position à partir de laquelle il constatera des matchings tous bons jusqu’à la fin de la chaîne.
    Sur cet exemple, le moteur de regex n'a pas à reculer de beaucoup: il recule d'1 caractère dans la chaîne examinée et il teste ce dernier caractère de la chaîne avec le dernier symbole de la RE: ah oui cette fois ça marche: \] de la RE matche avec le dernier caractère ']' de la chaîne examinée.
    Il est content, il s’arrête.

    Et si on lui demande d’afficher les trois groupes (.*) , on obtient:
    ('glolo ', ' tabaloulou AfficheClics=1 tabalala gytew', '')
    car le second groupe (.*) a matché comme un fou jusqu’à l’avant-dernier caractère, ne laissant rien à matcher au troisième groupe (.*).



    ----------------------------------




    Je ne suis pas tellement d’accord non plus avec la traduction proposée pour
    (?: (.*?)AfficheClics=([01]))? :
    Citation Envoyé par Eric2a #15 Voir le message
    d'éventuels caractères effectivement suivis de "AfficheClics=[0 ou 1]"
    Dans un premier temps, la présence de (.*?) accolée à AfficheClics=([01]) à l’intérieur de parenthèses me chiffonait parce que le caractère facultatif exprimé par l’étoile dans (.*?) se trouve ainsi doublée par le ? terminal.

    J’ai donc essayé de sortir (.*?) de l’expression parenthésée (?: AfficheClics=([01]))?

    Mais là, surprise, je suis tombé sur un effet dont je ne m’étais jamais rendu compte:
    le matching de la RE
    mobile(.*?)(?: AfficheClics=([01]))? (.+?)tew
    avec la chaîne "automobile tabalou AfficheClics=1 tabala gytewrhu"
    sort comme capture de groupes:
    groups = ('', None, ' tabalou AfficheClics=1 tabala gy')
    et pas moyen d’obtenir autre chose.

    Si on enlève le ? après (?: AfficheClics=([01])) on obtient:
    groups = (' tabalou ', '1', ' tabala gy')

    Si on garde le ? à la fin de (?: AfficheClics=([01]))? , mais qu’on ne stoppe plus la gourmandise de (.*) on obtient
    groups = (' tabalou AfficheClics=1 tabala g', None, 'y')

    Le résultat
    groups = ('', None, ' tabalou AfficheClics=1 tabala gy')
    est donc lié au fait que la RE élémentaire (.*?) comporte à la fois
    - une étoile * qui exprime du facultatif devant une RE élémentaire elle-même facultative (?: AfficheClics=([01]))?
    - et un ? qui fait dépendre l’avancée de (.*?) de la présence ou non du motif (?: AfficheClics=([01])) dans la chaîne examinée.

    Avec un peu de réflexion, cela paraît presque compréhensible.
    Quand le moteur de regex arrive sur (.*?) , il constate qu’il n’est pas obligé de trouver un match (à cause de la présence de *) et qu’il lui faut regarder la suite (à cause du ?) ;
    cette suite est une RE élémentaire facultative aussi.
    Deux RE facultatives se succédant => il décide manifestement de commencer à considérer comme première hypothèse que la RE élémentaire (?: AfficheClics=([01]))? ne matchera rien, de faire matcher (.*?) avec le minimum possible, et de poursuivre la vérification du matching au delà:
    c’est possible puisqu’il trouve ensuite (.*?) à nouveau à matcher et cela le mène en matching jusqu’à ’tew’ qui stoppe le matching de (.*?).

    Comme ça marche, càd le matching a pu être tenu jusqu’au bout, le match qui sort est avec (?: AfficheClics=([01]))? qui ne matche rien (None) et le premier groupe (.*?) qui matche avec une chaïne de longueur nulle.

    Ce qui se passe a l’air en effet assez subtil: (.*?) n’est pas en non-matching, il est en matching avec une chaîne de longueur nulle, symbolisée par ''.

    Enfin bref, constatons que l’expression (.*?)(?: AfficheClics=([01]))? fait que (.*?) n’attrape donc pas ce qui se trouve devant ’AfficheClics’.
    J’y vois la confirmation qu’un moteur de regex avance en examinant chaque RE élémentaire l’une aprés l’autre et en diagnostiquant immédiatement quelque chose pour la RE en examen, sans aller loin dans la série de REs. Il ne revient en arrière que s’il y est obligé par ce qu’il trouve finalement plus loin.




    Ceci étant, tu as donc raison, Eric2a, d’avoir écrit (?: (.*?)AfficheClics=([01]))?

    Par contre, comme le ? de (.*?) rend indissociables (.*?) et AfficheClics=([01]) , cela a la conséquence suivante:
    le groupe (.*?) ne détecte quelque chose que si un tronçon "Affiche=0 ou 1" existe dans la chaîne examinée. Sinon il renvoie None.

    Pour moi,

    ((.*?)AfficheClics=([01])) se lit donc plutôt:
    « chaîne "AfficheClics=([01])" éventuellement précédée d’une chaîne quelconque »

    et ((.*?)AfficheClics=([01])) ? : « présence éventuelle de la chaîne "AfficheClics=([01])" éventuellement précédée, si elle existe, d’une chaîne quelconque »

    et non pas dans l’autre sens.





    ---------------------




    Quant à (.*) (?: AfficheClics=([01]))? (.*)\] on a vu qu’il vaut mieux regarder jusqu’où matche chaque RE élémentaire prise individuellement plutôt que de chercher à nommer l’ensemble.

    Ce qui m'amène à revenir au début:
    si ce n’est pas la succession de trois REs (.*)(expression facultative)(.*) qui est cause du problème, quelle est la véritable cause ?

    Pourquoi l’ajout de ? permet d’obtenir le bon résultat ?
    Pourquoi enlever l’option s (c’est à dire rendre le point non matchant avec les \n) a-t-elle le même effet ?
    Dans les deux cas, ce sont des facteurs de limitation de l’avancée du moteur de regex, mais pas de façon similaire.

    Pour moi, le mystère n’est toujours pas éclairci et je crains qu'on n'ait jamais le fin mot.

  20. #20
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    et en rajoutant l'option u ?

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

Discussions similaires

  1. Soucis avec l'option "Bridged" sur VMWARE
    Par Jovan dans le forum VMware
    Réponses: 1
    Dernier message: 10/02/2015, 15h50
  2. Recherche RPG avec option coopération sur PS3
    Par clairetj dans le forum Consoles
    Réponses: 13
    Dernier message: 08/07/2014, 08h35
  3. Réponses: 14
    Dernier message: 21/09/2012, 14h05
  4. [WD10] plantage appli avec vista sur impression Etat
    Par mnssylvain dans le forum WinDev
    Réponses: 3
    Dernier message: 27/11/2008, 19h02
  5. Réponses: 3
    Dernier message: 04/11/2007, 19h55

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