RegExp problème...

Petit nouveau ! | 6 Messages

22 janv. 2008, 21:45

Bonjour à tous !

Voici mon petit problème : J'essaye désesperemment de ne prendre que les liens d'une page.
Mais le problème étant que je prend aussi les images mais je ne comprend pas pourquoi.

Je ne demande pas forcément de solutions mais plutôt pourquoi j'obtient cela.

Code : Tout sélectionner

<?php $option = file_get_contents('http://www.allocine.fr/recherche/?motcle=' . urlencode('Hooligans')); $recup_url = '`<a .*href="[^>].+fichefilm_gen_cfilm.+">`'; preg_match_all($recup_url, $option, $url); $count = count($url[0]); for($i=0;$i<$count;$i++) { echo $url[0][$i],'<br/>'; } ?>

Merci par avance.

ViPHP
ViPHP | 5924 Messages

22 janv. 2008, 22:56

Tu peux donner les résultats que tu obtiens ? (enfin quelle tête ca a…)

Petit nouveau ! | 6 Messages

22 janv. 2008, 23:07

J'ai trouvé la réponse à ce que je cherchais...ou presque :)

Code : Tout sélectionner

<?php require_once('functions.php'); $option = file_get_contents('http://www.allocine.fr/recherche/?motcle=' . urlencode('Death Sentence')); $recup_url = '`<a .*href="[^>](.+fichefilm_gen_cfilm.+)" class`'; preg_match_all($recup_url, $option, $url); echo 'http://www.allocine.fr/' , $url[1][0],'<br/>'; ?>
Cela fonctionen parfaitement j'obtiens bien ce que je cherchais mais s'il n'y a pas de résulatt il m'en trouve un lus bas dans la page mais je ne le veux pas :)

Donc je vais chercher quelque chose pour combler ce problème.

Merci

Mammouth du PHP | 505 Messages

23 janv. 2008, 10:51

Je suis étonné que tu trouves que cela fonctionne avec cette regexp.

Si j'ai bien compris, tu souhaites récupéré tous les href qui contiennent fichefilm_gen_cfilm

Dans ta regexp, je vois plusieurs pb.

Code : Tout sélectionner

`<a .*href="[^>](.+fichefilm_gen_cfilm.+)" class`
dans l'ordre.
- Tu match un espace, hors cela peut etre une tabulation
- tu met .*, c'est "Greedy", c'est a dire que tu ne matchera pas la plus petite occurence, si tu as 2 a de suite, tu n'en verra probablement qu'un, il faut soit utiliser le modificateur U, soit rendre ungreddy avec le ?, soit .*?
- Tu match " mais cela pourrais etre '
- .+ est greedy
- .+ est greedy
- Tu match " mais cela pourrais etre '
- Tu match un espace, hors cela peut etre une tabulation
- tu match class, cela pourrait etre n'importe qu'elle autre attribut avant class.

- Tu sous entend l'ordre des attributs, href, puis class
- Tu n'ignore pas la casse. <A ne matcherait pas, ni "HREF="

Je te propose d'étudier la regexp suivante et de voir si elle convient a ce que tu souhaites faire.


$recup_url = '/<a[^>]+?href=["\']([^"\']*?fichefilm_gen_cfilm[^"\']*?)["\'][^>]*?>/i' ;

[/code]

Petit nouveau ! | 6 Messages

23 janv. 2008, 11:22

Hello !

Merci beaucoup pour toutes ces précisions !

Je pensais que ceci : [^>]+? voulait dire ne contient pas le caractère >, le + voulant dire contient au moins un caractère ou plus et le ? expliqaunt qu'il peut y avoir ou pas.

Je pense que j'ai un gros problème vis à vis de ce genre de regexp : [^>]+?, pourrais-tu men dire davantage s'il te plait sur la regexp que tu as faite histoire que je me calle correctement avec ce genre d'expression.

Merci en tout cas :)

Mammouth du PHP | 505 Messages

23 janv. 2008, 12:22

[^>]+? : On vas découper pour expliquer chaque token

[^>] : C'est une classe négative de caractère, ici, cela signifie n'importe quelle caractère sauf le >. Dans le contexte, c'est beaucoup plus performant que d'essayer de lister les caractères autorisés car il n'y a qu'un seul test.

+ : Comme tu l'a dis, c'est un quantificateur équivalent a {1,} soit de 1 a n

? : C'est le ungreddy: En clair, dans une classe négative, cela n'a pas de sens, le fait de l'expliquer me fait réaliser que j'ai écrit une regexp un peu a l'arrache, tu peut les supprimer. Dans une classe positive [a]+?, c'est en revanche tout a fait différent.
Sur la chaîne "aaaaa", [a]+ vas matcher 1 fois "aaaaa", sur la même chaîne, [a]+? vas matcher 5 fois, a chaque fois, il prend la plus petite partie qui match. La ou c'est vraiment important, c'est quand tu as des .*, car le . match tout. Et sur la chaîne "toto et titi sont dans un bateau; toto tombe a l'eau;", si tu cherche tout ce qui se trouve entre toto et le ; avec "toto.*;" tu matches les 1 seule fois les 2 phrases d'un coup. Avec "toto.*?;" tu matches 2 fois, une phrase a la fois.

Donc la regexp corrigé donne (elle match la même chose, mais les ? devant les classe négative ne servaient a rien)
$regexp = '/<a[^>]+href=["\']([^"\']*fichefilm_gen_cfilm[^"\']*)["\'][^>]*>/i' ;

Petit nouveau ! | 6 Messages

23 janv. 2008, 12:45

Merci beaucoup pour ces infoirmatiosn elles m'ont beaucoup servi et principalement sur une meilleure compréhension du "?".

J'ai une autre question si cela ne te dérange pas.

Code : Tout sélectionner

$option = file_get_contents('http://www.allocine.fr/film/fichefilm_gen_cfilm=54456.html); $recup_url = '`<div align="justify"><h4>(.*)?</h4></div>`i'; preg_match_all($recup_url, $option, $url); var_dump($url[1]);
Voici comment j'ai créer cette regexp tout simple :

1) Je regarde dans le code source ou se trouve le synopsis.
2) Je vois qu'il commence par "<td style="padding: 10px 0pt 0pt;" valign="top"><div align="justify"><h4>" et qu'il se fini par "</h4></div></td>"

3) Je commence donc ma regexp en commencant par `<div align="justify"><h4>`

4) Puis je voudrais tout ce qui se trouve entre donc je met des parenthèses `()`

5) Je veux tous les caractères donc dans les parenthèses je met `.*`. Ce qui me donne `(.*)`

6) Je met un ? pour matcher plusieurs fois la même chose si elle se produit (si j'ai bien suivi ton post précédent je ne devrait pas me tromper sur ce sujet)

7) Puis je ferme mes balises `</h4></div>`

8) Et enfin je met un "i" à la fin qui lui dit dene pas tenir compte des majuscules/minuscules.

Le problème étant qu'il me matche bien une phrase mais ce qu'il y'a en dessous du synopsis, ils sont les mêmes début mais pourtant il ne me match pas le tyout premier qu'il devrait trouver c'ets à dire le synopsis.

Quel est mon problème ?

Merci encore une fois pour tes réponses clares !

ViPHP
ViPHP | 4039 Messages

23 janv. 2008, 13:05

Un petit truc encore alors: Correspond certes à "n'importe quel caractère", mais pas à un retour à la ligne (ça dépend, je sais).. or dans le synopsis, il y en a.

Il faut donc mieux le remplacer par

Code : Tout sélectionner

[\s\S]*
Qui est en gros: Tout ce qui est un espace blanc (donc un retour à la ligne aussi) et tout ce qui ne l'est pas. C'est pareil, mais pas tout à fait.

Sinon, pourquoi ne pas simplement te baser sur "synopsis" pour orienter ta recherche ? quelque chôse comme ceci:

Code : Tout sélectionner

Synopsis[\s\S]*?<h4>([\s\S]*?)</h4></div>
Ne devrait te retourner qu'un seul résultat: le bon.

C'est juste que c'est pas ce qu'il y a de plus optimisé, mais ça marche.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

Petit nouveau ! | 6 Messages

23 janv. 2008, 13:12

Merci poru ton aide mais il y'a quelque chose que je ne comprend pas dans ce regexp :

Code : Tout sélectionner

Synopsis[\s\S]*?<h4>([\s\S]*?)</h4></div>
Théoriquement il devrait prendre tout ce qu'il y'a entre synopsis et le </h4></div>, la dessus on est d'accord.

Pourquoi dans le code que tu m'a donné il me donne juste le texte ?
Pourquoi n'ai-je pas ceci avec

Code : Tout sélectionner

</b></h3></td></tr></table> <table cellpadding="0" cellspacing="0" border="0" style="width: 100%;"><tr><td style="padding: 5 5 0 5" valign="top"> <table cellpadding="0" cellspacing="0" border="0" width="100%" style="padding: 0 0 0 0;"> <tr>
Ce code est le code qui se trouve juste après le mot synopsis et avant le début du texte en lui même.

Another question (oui je sais je suis chiant mais j'ai soif d'apprendre les regexp en ce moment :)), le "\s" poru moi c'était les espaces bon ca oki.
Le "\S" ca je ne savais pas c'est tout ce qui n'est pas un espace ?
Et les retours à la lignes théoriquement ce n'est pas "\r" et/ou "\n" ?

Merci pour vos réponses rapides en efficaces, j'apprend beaucoup ici !

ViPHP
ViPHP | 4039 Messages

23 janv. 2008, 14:58

\s est un terme réunissant le groupe des "espaces blancs" : \t\r\n\v\f. Donc que ton retour de ligne soit \n ou \r\n, \s* le validera (l'un à la suite de l'autre).

Pour le S majuscule, c'est comme avec les \d et les \w (pour les chiffres et les lettres). \d valide un chiffre, mais \D valide tout ce qui ne l'est pas. Pareil avec le \s donc.

Dans mon code, regarde bien ce qui est en gras:
Synopsis[\s\S]*?<h4>([\s\S]*?)</h4></div>
a partir de Synopsis, je valide tout ,[\s\S]*?, jusqu'au premier <h4>. Ensuite, je mets la parenthèse capturante pour tout ce qui se trouve entre ce <h4> jusqu'a </h4>, ([\s\S]*?). J'aurais pu exclure le </div>, mais bon.

Donc, le texte qui se trouve entre synopsis et <h4> est trouvé, mais n'est pas repris dans la parenthèse capturante. Bien sur, j'aurais pu passer cette étape, et récuperer le texte par après en le nettoyant, mais vu que regex te permets de ne récuperer que ce que tu veux par l'intermédiaire des parenthèses capturantes, pourquoi s'en priver.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

Mammouth du PHP | 505 Messages

23 janv. 2008, 15:23

Pour répondre à ton poste 11h45 sur le synopsys.

ton erreur se situe sur le (.*)?

(.*)? Signifie capture n'importe quel caractère de 0 a n fois, sachant qu'il capturera le max possible, et le ? a l'extérieur des parenthèses est vu comme un quantificateur signifiant 0 ou 1. En gros, il n'a aucune incidence puisque le quantificateur interne (l'étoile) couvre la même plage.

Ce que tu voulais faire, c'est plus probablement (.*?), ou tu captures la plus petite chaîne possible.

Concernant la remarque de Berzemus, le . match effectivement tous les caractère sauf le newline (soit \n et/ou \r). Si tu veux matcher le newline, le plus simple est encore d'ajouter le modificateur m (pour multiple line).
Enfin, moi perso, je trouve plus simple et plus lisible /(.*)/m que /([\s\S]*)/ même si au final, cela revient au même. Ce qu'il faut savoir, c'est qu'il y a souvent beaucoup de solution qui aboutissent au même résultat en regexp.

Duand tu as une classe de base type \d, \D signifie la négation de cette classe de base. Pour \s, c'est la meme chose \S match tout ce qui n'est pas matché par \s (espace, tab, CR LF). C'est aussi vrai pour l'assertions d'ancrage \b pour limite de mot et \B pour une non limite de mot.

La piste que te donne berzemus est la bonne. Il faut trouver une "ancre" qui te permet d'identifier l'approche de la chaine que tu souhaites matcher, et ensuite, capturer uniquement par apport a cette ancre, la sous chaine qui t'interesse. En l'occurence, après le mots sysnopsis (ton ancre), tout ce qui se trouve entre les premiers h4 que tu rencontres.

Une autre syntaxe:

Code : Tout sélectionner

/\bSynopsis\b.*?<h4>(.*?)</h4>/im

Mammouth du PHP | 505 Messages

23 janv. 2008, 15:25

grilled by berzemus :)

Petit nouveau ! | 6 Messages

23 janv. 2008, 15:35

Merci infiniment pour toutes ces superbes réponses que vous m'avez donnée !

Il est vrai que je constate que s'y connaitre en regexp est un grand plus mais les regexp sont aussi tellement vaste que je ne vais pas tout maitriser (malheureusement :p) tout de suite !

Je vais créer mes propres notes pour les regexp grace à vos réponses :)

@+