Page 1 sur 1

preg_match() retourne Array ( )

Posté : 14 avr. 2016, 14:46
par zork
Bonjour à tous,

Je me remets au développement après une dizaine d'années d’interruption, et le redémarrage n'est pas évident sur certains points :mrgreen:.

Je tente d'écrire un programme dont l'une des fonctionnalités de base est de récupérer des informations sur des sites très ciblés, dans le but d'en reformater le contenu.

Pour ce faire, j'ai recours assez souvent à la fonction preg_match().

Si dans la majorité des cas, tout se passe comme attendu, je but bien méchamment sur des récupérations que je qualifierais de récalcitrantes :roll:. Le "hic", c'est que je n'arrive pas du tout à voir où se trouve mon erreur, et ce n'est pas faute d'avoir pris le problème dans tous les sens, d'où mon appel à l'aide d'aujourd'hui.

Avant d'aller plus loin, voici un petit bout qui fonctionne parfaitement :
$sortie = NULL;
                    $code = NULL;
                    
                    //balise incluant le nom de l'auteur (donc alétoire) il faut découper la chaine en deux temps
                    $code = '#<h2 class="user-info__username">(.*)\</h2>#Ui';
                    preg_match($code, $contenu, $sortie);
                    $contenu = $sortie[1];
                    $code = '#rel="author">(.*)\</a>#Ui';
                    preg_match($code, $contenu, $sortie);
                    return $sortie[1];
Ici, pas de soucis donc.

Mais sur les deux exemples qui suivent, impossible d'obtenir l'information recherchée.
Récupération de la date de création

La ligne que j'essais de récupérer se présente sous cette forme :
<time itemprop="dateCreated" datetime="2016-04-14T16:45:47+10:00">
              14 April 16
            </time>
J'utilise un code très proche du précédent, que voici :
$sortie = NULL;
                    $code = NULL;
                    
                    //la balise incluant la date de création (donc alétoire) il faut découper la chaine en deux temps
                    $code = '#<time itemprop="dateCreated"(.*)\/time>#Ui';
                    $contenu = preg_match($code, $contenu, $sortie);
                    
                    $code = '#>(.*)\<#Ui';
                    preg_match($code, $contenu[1], $sortie);
                    
                    print_r($sortie);
                    return $sortie[0];
Lorsque je tente de voir ce que contient la variable de cette manière :
print_r($sortie);
J'ai toujours le même résultat : Array ( )

Récupération d'URLs dans une page
Deuxième exemple où cela ne fonctionne pas du tout, lorsque je tente de récupérer une liste d'URLs contenu dans une autre page.

Voici comment se présente le code dans la dite page :
<a class="js-google-analytics__list-event-trigger t-link -color-inherit -decoration-reversed" href="/item/monitem/123456789?s_rank=1">Item - Titre item</a>
        </h3>
La différence ici, avec le code précédent, c'est que cette structure devrait être retrouvée une soixante de fois dans la page. J'utilise donc ce bout de code :
$contenu = NULL;
                    $contenu = $this->contenu_page;
                    $code = '#decoration-reversed(.*)s_rank>#Ui';
                                        
                    preg_match($code, $contenu, $sortie, PREG_OFFSET_CAPTURE);
Mais le résultat est comme pour l'exemple précédent, un array vide (Array ( ) );

J'ai tenté de réécrire plusieurs fois le $code pour le faire le plus simple possible, sans succès. Je n'arrive pas à voir où se trouve mon (mes) erreur(s).

En vous remerciant chaudement par avance :wink:.

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:04
par or 1
une idée vite fait, voir si cela ne fonctionne pas mieux sans retour à la ligne dans le html.

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:07
par Ryle
Bonjour,

Si ton texte est sur plusieurs lignes, il faut utiliser l'option "s" dans ton expression régulière afin que le point "." considère les retours à la ligne comme faisant partie de "n'importe quel caractère" :)

Tu peux t'appuyer sur certains sites pour tester tes expressions régulières et comprendre ce qu'elles retournent et pourquoi. Personnellement j'aime bien celui-ci : https://regex101.com/ mais tu peux aisément en trouver d'autres :)

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:09
par Spols
Hello,

j'ai toujours eu beaucoup de mal avec les expression régulière, donc je te comprends.
Si tu cherche des informations dans du code de type HTML ou XML, les outils de DOM Document de php sont très puissant et permette ce genre de chose assez facilement. La doc sur PHP.net est bien foutue.
Mais je suis conscient que cela demande de réécrire beaucoup de code.

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:12
par @rthur
3 réponses en moins de 10 minutes, on est chaud sur PHPfrance ! ;-)

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:35
par zork
3 réponses en moins de 10 minutes, on est chaud sur PHPfrance ! ;-)
Tellement que j'ai pas eu le temps de bien répondre à la première intervention :mrgreen:

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:38
par zork
une idée vite fait, voir si cela ne fonctionne pas mieux sans retour à la ligne dans le html.
Salut Or 1

Maintenant que tu me le dis, je me souviens l'avoir lu dans mes recherches. Pour être certain que cela ne soit pas la source de l'erreur, j'ai inséré ce petit morceau de code (mais le résultat est toujours le même ;)
$this->contenu_page = $this->retirer($this->contenu_page, 'retour_ligne');
switch($a_retirer){
                
                case 'retour_ligne':
                    $str = str_replace("\n", "", $contenu_page);
                    $str = str_replace("\r\n", "", $str);
                    $str = str_replace("\r", "", $str); 
                    $str = str_replace(CHR(10),"",$str);
                    $str = str_replace(CHR(13),"",$str);
                    $contenu_page = $str;
                    return $contenu_page;
                    break;
Au moins maintenant, j'ai tout le html sur une seule ligne ;)

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:48
par zork
Hello,

j'ai toujours eu beaucoup de mal avec les expression régulière, donc je te comprends.
Si tu cherche des informations dans du code de type HTML ou XML, les outils de DOM Document de php sont très puissant et permette ce genre de chose assez facilement. La doc sur PHP.net est bien foutue.
Mais je suis conscient que cela demande de réécrire beaucoup de code.
Hello Spols,

je ne suis donc pas le seul à souffrir avec les RegEx... Ça me rassurerais presque dis donc :mrgreen:.

Je ne connaissais pas l'existence de DOM document, et maintenant, c'est un peu tard, car je but uniquement sur ces deux éléments. Ça me ferait mal de tout réécrire juste pour ces deux éléments :roll:.

Je vais bien finir par trouver la solution. Je me pencherais sur DOM Document à la version 2.0 :lol:.

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 15:54
par or 1
https://regex101.com/r/rW3vA0/1
ton expression fonctionne, la première aussi.

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 17:46
par Ryle
Si ton texte est sur plusieurs lignes, il faut utiliser l'option "s" dans ton expression régulière afin que le point "." considère les retours à la ligne comme faisant partie de "n'importe quel caractère" :)

Tu peux t'appuyer sur certains sites pour tester tes expressions régulières et comprendre ce qu'elles retournent et pourquoi. Personnellement j'aime bien celui-ci : https://regex101.com/ mais tu peux aisément en trouver d'autres :)
:roll:

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 19:00
par zork
Ayant posé deux questions, je vais répondre à l'une et en suite à l'autre :)

Pour la partie sur la date voici mon nouveau code, et cela fonctionne parfaitement :
case 'date_creation':
                    $sortie = NULL;
                    $code = NULL;
                    
                    $code = '#<time itemprop="dateCreated" datetime="(.*)">#Uis';
                    preg_match($code, $contenu, $sortie);
                    
                    print_r($sortie);

                    return $sortie[1];
                    break;
Grâce au test de RegEx en ligne, je me suis aperçu que l'expression semblait ne pas passer. En la remaniant un peu, cela fonctionne beaucoup mieux. Je ne saurais dire ce qui n'allait pas...

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 19:10
par zork
Pour la deuxième partie, je ne sais pas si je dois continuer dans ce thread, ou en ouvrir un autre. En effet, cela fonction "à moitié".

Je m'explique. Voici mon code :
$contenu = NULL;
                    $contenu = $this->contenu_page;
                    $code = '#<a class="js-google-analytics__list-event-trigger t-link -color-inherit -decoration-reversed" href=(.*)<\/h3>#Uis';
                                        
                    preg_match($code, $contenu, $sortie, PREG_OFFSET_CAPTURE);
  
                    print_r($sortie);
                    echo '<br>';
le print_r me sort cela :
Array
(
    [0] => Array
        (
            [0] => <a class="js-google-analytics__list-event-trigger t-link -color-inherit -decoration-reversed" href="/item/mon_item/15275636?s_rank=1">Item - Nom Item</a>        </h3>
            [1] => 146507
        )

    [1] => Array
        (
            [0] => "/item/mon_item/15275636?s_rank=1">Item - Nom Item</a>        
            [1] => 146606
        )

)
À première vue, cela pourrait sembler bien fonctionner, mais...

Je suis censé avoir une soixantaine d'URLs dans cette page, et je pensais que le PREG_OFFSET_CAPTURE servait à cela, mais cela ne semble pas être le cas.

En outre, je ne comprends pas du tout la deuxième position de l'Array, d'où sorte ces chiffres. Ce n'est pas bien grave en soit, mais je n'aime pas ne pas comprendre :mrgreen:.

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 19:16
par zork
Ok, je pense ne pas du tout avoir compris ce que veux dire cette description :
PREG_OFFSET_CAPTURE
Si cette option est activée, toutes les sous-chaînes qui satisfont le masque seront aussi identifiées par leur offset. Notez que cela modifie la valeur de matches qui devient un tableau dont chaque élément est un tableau contenant la chaîne correspondant au masque à l'offset 0 ainsi que l'offset de la chaîne dans subject à l'offset 1.
Quoi qu'il en soit, preg_match_all() semble bien mieux correspondre à mon attente :
Analyse subject pour trouver l'expression pattern et met les résultats dans matches, dans l'ordre spécifié par flags.

Après avoir trouvé un premier résultat, la recherche continue jusqu'à la fin de la chaîne.
je vais creuser de ce côté la :mrgreen:

Re: preg_match() retourne Array ( )

Posté : 14 avr. 2016, 19:19
par zork
Ok... Je m'avance peut-être un chouillat, mais juste ajouter le "all" semble tout résoudre :mrgreen:.
$contenu = $this->contenu_page;
 $code = '#<a class="js-google-analytics__list-event-trigger t-link -color-inherit -decoration-reversed" href=(.*)<\/h3>#Uis';
                                        
 preg_match_all($code, $contenu, $sortie);