8722 sujets

Développement web côté serveur, CMS

Modérateur
Bonjour,

Je cherche à sortir d'un texte toutes les lignes qui contiennent un mot clé spécifique mais je ne vois pas du tout comment m'y prendre.

Est-ce que vous pourriez me mettre sur la voie s'il vous plaît ?

Par exemple, j'ai au format texte ceci
La nuit tous les chats sont gris.
Le jour ils m'apparaissent blanc.
Mais si le temps est gris, ils virent au noir.
Alors que par magie, ils disparaissent sous mes yeux.

L'idée serait de récupérer les lignes qui contiennent le mot 'gris', donc obtenir:
$result = array(
 [0] => 'La nuit tous les chats sont gris.'
 [1] => 'Mais si le temps est gris, ils virent au noir.'
);


Par avance, merci.
Modérateur
Hello,

il faudrait convertir ta chaîne en tableau puis utiliser preg_grep:


$a = array('La nuit tous les chats sont gris.',
 "Le jour ils m'apparaissent blanc.",
 "Mais si le temps est gris, ils virent au noir.",
 "Alors que par magie, ils disparaissent sous mes yeux."
);
$result = preg_grep('/gris/', $a));


un petit explode ou preg_split devrait permettre d'obtenir le tableau
Modérateur
Yeees ! Je comprends la démarche et découvre par le fait une nouvelle fonction qui manquait à mon arsenal.

Merci Kustolovic, c'est pile poil ce que je cherchais. Smiley ravi
Bonjour.

Il y a aussi preg_match_all. (Edit : le point ne permet pas de capturer le retour chariot. C'est pour ça que chaque ligne est traitée séparément.)

$resultats = preg_match_all('/.*?gris.*/ui', $texte, $matches);


$matches contient les deux lignes. (enfin, un tableau qui contient un tableau qui contient deux lignes)
(J'ai mis un point d'interrogation derrière la première étoile pour éviter trop de récursivité.)
Il est à noter que c'est la chaîne 'gris' qui est cherchée et non le mot gris.
ui : u pour l'unicode et i pour l'insensibilité à la casse.

Smiley smile
Modifié par Zelena (23 Jun 2017 - 13:51)
Meilleure solution
Modérateur
Zelena a écrit :
[...]
Si je suis bien l'affaire, preg_match_all() ne m'affranchit pas de mettre le texte dans un tableau au préalable, exact ?

Je parle bien de chaine et non de mot, tu as raison de l'évoquer. 'gris' ne fait que servir le sujet, en réalité la chaine contiendra certainement des signes.
Modérateur
Greg_Lumiere a écrit :
Si je suis bien l'affaire, preg_match_all() ne m'affranchit pas de mettre le texte dans un tableau au préalable, exact ?

Si si, ça marche avec la string directement. D'ailleurs c'est une bonne idée à laquelle je n'avais pas pensé Smiley smile

Ma méthode te renvoie les numéro de lignes par contre (en index) si ça t'es utile.

Il doit y avoir des différences de performances (qui mériteraient d'être testées) si tes données sont de grande quantité. (Mais à mon avis les deux méthodes sont mauvaises pour ce cas).
Modérateur
kustolovic a écrit :

Si si, ça marche avec la string directement.
C'est bon à savoir Smiley lol

kustolovic a écrit :
Il doit y avoir des différences de performances (qui mériteraient d'être testées) si tes données sont de grande quantité. (Mais à mon avis les deux méthodes sont mauvaises pour ce cas).
De toute façon dès lors qu'on utilise une regexp les perfs en subissent les conséquences. C'est un sacrifice à mesurer à bon escient mais que s'il est indispensable doit être mis en application.
Pour le moment le volume ne semble pas pharaonique. A terme je devrais soit découper le travail soit revoir la méthode dès la base.

En tout cas c'est super, je vais pouvoir potasser ça sachant que je vais maintenant dans la bonne direction.


Néanmoins il me reste une question en suspend...
Modérateur
$resultats = preg_match_all('/.*?gris.*/ui', $texte, $matches);


Qu'est ce qui dit dans le pattern de s'arrêter au saut de ligne pour capturer $matches ?
Greg_Lumiere a écrit :
$resultats = preg_match_all('/.*?gris.*/ui', $texte, $matches);


Qu'est ce qui dit dans le pattern de s'arrêter au saut de ligne pour capturer $matches ?


Mais… mais… je l'ai dit. Smiley bawling . Le point ne permet pas de capturer le retour chariot. C'est pour ça que chaque ligne est traitée séparément. C'est bien pour ça qu'il s'agit de preg_match_all et non de preg_match : il trouve une correspondance, puis une autre, etc…

Smiley smile
Modérateur
Zelena a écrit :
Le point ne permet pas de capturer le retour chariot.

Pour être tatillon, excepté en cas de compilation particulière, par défaut le point ne permet pas de capturer la nouvelle ligne Smiley smile
Modifié par kustolovic (23 Jun 2017 - 15:20)
kustolovic a écrit :

Pour être tatillon, excepté en cas de compilation particulière, par défaut le point ne permet pas de capturer la nouvelle ligne Smiley smile


En ce qui me concerne, M. Kustolovic, soyez tatillon autant qu'il vous plaira.
Smiley smile
Modérateur
Haa conichoa ! J'entends clair et fort maintenant. En fait le retour chariot agit comme un délimiteur de fin implicite.
Modérateur
Bonjour,

Ça marche du tonnerre et je vous remercie pour le coup de main. Ça m'a facilité le traitement de mes textes.

Dans la même veine, j'ai maintenant besoin de travailler sur des fichiers Css et malheureusement, cette solution n'est pas envisageable en l'état.

Le but est de sélectionner le paragraphe qui contient un sélecteur particulier.

Par exemple dans
body {
properties;
}
body li a {
properties;
}
body div {
properties;
}
disons que je souhaite récupérer le paragraphe qui contient " li ".

Pour ce faire j'entends utiliser preg_match_all() avec un pattern du style:
du début de la ligne qui contient li + multiples caractères + { + multiples caractère et sauts de ligne/retour chariot + qui finit par }

Du coup, après maintes et maintes essais, je dois avouer sécher

A l'heure actuelle ma recherche en est au stade
$result = preg_match_all('/(^.*li.*\{(.|\n)+\}$)/mui', $css, $matches);

$matches devient alors un tableau à plusieurs entrées vides.

Pourtant ça me paraît logique. Voici comment je vois la chose:
^.* : du début de ligne, n'importe quel caractère
li : mon mot clé (j'ai occulté l'espace temporairement, je n'y vois pas le jour)
.* : n'importe quel caractère qui suit mon mot-clé
\{ : j'échappe l'accolade ouvrante qui est un caractère spécial
(.|\n)+ : n'importe quel caractère sur plusieurs lignes
\{$ : capture jusqu'à la première accolade fermante trouvée
/m : multiligne d'après la doc ; ça me laisse dubitatif


La question est simple, où est donc mon erreur ?
Même question au pluriel Smiley cligne


PS : à y repenser, je me dis que là je n'avais vu la chose que si tous les sélecteurs sont sur la même ligne or ce n'est pas forcément le cas. Je pense qu'au lieu de remonter jusqu'au début de la ligne. Il me serait donc préférable de capturer depuis l'accolade fermante précédente moins 1 caractère (l'accolade elle-même).
Modifié par Greg_Lumiere (25 Jun 2017 - 09:59)
Bonjour.

Je ne dis pas que j'ai la réponse mais juste quelques pistes :
— d'abord le m pour "multiligne" concerne uniquement les ancres ^ et $ , et dans ce cas début et fin des lignes et non début et fin de la chaîne (Edit : j'étais trompée…) (« Multi-line mode only affects anchors, and single-line mode only affects the dot. » in http://www.regular-expressions.info/dot.html);
— ensuite, .* est redoutable. Si on fait .*li, ça ne veut pas dire : « Je prends tous les caractères jusqu'à ce que je trouve la chaîne li, mais je prends tous les caractères que je peux prendre et à la fin, j'en abandonne deux, je rajoute "li" et je regarde si ça correspond. C'est le mode "greedy". Parfois, c'est la même chose, souvent, ça n'est pas le cas.
— il vaut mieux construire sa regex petit à petit que tout d'un coup. Je me suis fait un programme, Seven Tears aussi, des petits logiciels existent sur le marché…

Smiley smile
Modifié par Zelena (25 Jun 2017 - 13:56)
Le résultat de mes cogitations :
.+?(?=li)li[^}]+}


On prend tous les caractères jusqu'au groupe (?=li) (un "lookahead" qui ne capture rien et qui est juste là pour servir de stop, s'il ne le trouve pas, il s'arrête et passe à la ligne suivante.
Si on le trouve, on le prend et on prend tous les caractères différents de l'accolade fermante [^}]+

Je ne dis pas que c'est parfait. Maintenant, je fais faire la vaisselle.

Smiley smile