Une recherche dans une variable avec un preg_match();

WRInaute accro
Hello !

Je souhaiterai vérifier dans une chaîne de catactère que plusieurs "bouts de caratères" n'y sont pas présent.

Je connais donc la possibilité de refuser des caractères :
[^abc]

En revanche je ne sais pas comment faire pour interdire dans mon expression plusieurs petits "bouts de caractères" :
ne pas avoir <a
ne pas avoir <h
etc..


Pouvez-vous me filer un petit coup de main svp.
Merci. :D
 
WRInaute passionné
Salut,

tu peux utiliser tout simplement eregi(); pour vérifier que les <a, <h etc... ne sont pas présents.

Un truc du genre :

<?php
$interdits = array('<a', '<h', '...');

foreach($interdits as $interdit){
if(eregi($interdit, $str)) {
echo "la chaine contient une expression interdite\n";
}
}
?>

Si tu cherches tout simplement à supprimer le code html : striptags();
 
WRInaute accro
non, non j'ai déjà des preg_replace() en place, et il me faut donc une solution pour introduire dans celui-ci ce que j'ai indiqué, de manière à ne pas prendre en compte certaine balise.

Il doit bien y avoir une solution pour lui dire différent de "ma chaîne".
 
WRInaute accro
J'ai vraiment besoin de ça..

N'y a t-il pas une solution avec un !<ca>, je ne sais pas moi..
Ils ont du y pensez tout de même non ???? pfff :cry:
 
WRInaute discret
thierry8 a dit:
Il doit bien y avoir une solution pour lui dire différent de "ma chaîne".

Ta question porte large, très large même. La négation implique l'utilisation des assertions. Il y a plusieurs types d'assertions, les 3 assertions de bases sont:
1) assertion simple (ou d'ancrage)
2) assertion arrière (positive ou négative)
3) assertion avant (positive ou négative)

Il y en a d'autres, comme l'assertion récursive que je ne maîtrise pas encore, l'assertion conditionnelle, l'assertion contextuelle, etc... Mais pour ton besoin, j'imagine que les 3 de bases seront suffisantes.

1- ASSERTION SIMPLE (ou d'ancrage)
Tu as probablement déjà utilisé ^abc$ ou ^ veut dire "commence par" et $ veut dire "termine par". Mais il est possible d'ancrer de façon logique par exemple (?>\w+) ancrera la recheche au niveau du mot, ou si tu préfères, la recherche sortira de cette parenthèse lorsqu'elle aura trouvé une séquence complète de lettres consécutives.

Par exemple, avec la chaine suivante:
"abcdef sont les 6 premières lettres de l'alphabet"
avec (?>\w+) la recherche sortira avec succès de la parenthèse sur:
a) abcdef
b) sont
c) les
d) premières
e) lettres
f) l
g) alphabet
et non pas sur chacun des caractères. Un ancrage permet d'évaluer rapidement en échec les fausses hypothèses, mais aussi de fournir un élément plus complet pour évaluer positivement ou négativement.

2- ASSERTION ARRIÈRE (positive ou négative)
Une fois que l'ancrage produit un succès, elle contient une séquence de caratères qu'on peut évaluer globalement, soit positivement (?<=...) ou négativement (?<!...). En poursuivant mon exemple précédant, disons que j'ai ((?>\w+)(?<!premières|alphabet)), alors la recheche sortira avec succès de cette interaction d'assertions sur:
a) abcdef
b) sont
c) les
d) lettres
e) l
puisque (?<!premières|alphabet) dit d'ignorer les mots premières et alpabet. Par contre, si je dis ((?>\w+)(?=!premières|alphabet)) alors:
a) premières
b) alphabet
puisque (?<=premières|alphabet) dit de considérer seulement les mots premières ou alphabet.

Tu te demandes probablement quel avantage une assertion positive peut avoir par rapport à (premières|alphabet)... théoriquement la vitesse. Mais aussi la possibilité de combiner assertion positive et négative.

Code:
  $chaine='test pour voir si tous les mots seront censurés sauf PressioN qui devrait demeurer';
  echo preg_replace('#(?:(?>\w+)(?<!(?i)pression))#','***',$chaine);
  /* JE VEUX CENSURER TOUS LES MOTS À L'EXCEPTION DE PRESSION
  (        => sous masque
  ?:       => non capturant
  (        => sous masque
  ?>       => assertion d'ancrage de recherche
  \w+      => tant qu'il y a une lettre de mot
  )        => fin de l'ancrage, donc mot complet ou échec
  (        => sous masque
  ?<       => assertion sur l'ancrage précédent
  !        => doit-être différent
  (?i)     => (avec l'option i, minuscule/majuscule)
  pression => du mot pression
  )        => fin de doit être différent
  )        => fin du sous masque
  */

On peut combiner les assertions arrières positive et négative:

Code:
  $chaine='test pour voir si pourvoir sera capturé ou non';
  preg_match_all('#(?:(?>\w+)(?<=pour|voir)(?<!pourvoir))#i',$chaine,$resultats);
  /* JE VEUX LES MOTS POUR ET VOIR, MAIS PAS LE MOT POURVOIR
  (         => sous masque
  ?:        => non capturant
  (         => sous masque
  ?>        => assertion d'ancrage de recherche
  \w+       => tant qu'il y a une lettre de mot
  )         => fin de l'ancrage, donc mot complet ou échec
  (         => sous masque
  ?<        => assertion sur l'ancrage précédent
  =         => doit-être égal
  poir|voir => à la combinaison de pour et voir
  )         => fin de doit être égal
  )         => fin du sous masque
  (         => sous masque
  ?<        => assertion sur l'ancrage précédent
  !         => doit-être différent
  pourvoir  => du mot pourvoir
  )         => fin de doit être différent
  )         => fin du sous masque
  */
  echo '<pre>';
  print_r($resultats);
  echo '</pre>';

3- ASSERTION AVANT (positive ou négative)
C'est le même principe qu'une assertion arrière, sauf que la définition est apportée avant le filtre, soit positivement (?=...) ou encore soit négativement (?!...). Ememples:
((?!premières|alphabet)(?>\w+) produira:
a) abcdef
b) sont
c) les
d) lettres
e) l
((?=premières|alphabet)(?>\w+) produira:
a) premières
b) alphabet

Code:
  $chaine='la vision de cette version de la belle et la bête laisse place à la rêverie';
  preg_match('#(?=la)(?>\w+)\W+(?!vision|version|belle)(?>\w+)#i',$chaine,$resultat);
  /* JE VEUX TROUVER 2 MOTS CONSÉCUTIFS
     DONT LE PREMIER SERA LA
     ET LE SECOND NE SERA PAS VISION OU VERSION OU ENCORE BELLE
  (                    => sous masque
  (                    => sous masque
  ?=                   => assertion avant positive
  la                   => le prochain mot doit-être la
  )                    => fin de l'assertion
  (                    => sous masque
  ?>                   => assertion d'ancrage de recherche
  \w+                  => tant qu'il y a une lettre de mot
  )                    => fin de l'ancrage, donc mot complet ou échec
  \W+                  => séparer par 1 ou plusieurs caractères non lettre
  (                    => sous masque
  ?!                   => assertion avant négative
  vision|version|belle => le prochain mot ne doit pas être vision|version|belle
  )                    => fin de l'assertion
  (                    => sous masque
  ?>                   => assertion d'ancrage de recherche
  \w+                  => tant qu'il y a une lettre de mot
  )                    => fin de l'ancrage, donc mot complet ou échec
  )                    => fin du sous masque
  */
  echo $resultat[0];

Désolée de t'amener du coté assertion des expressions rationnelles, mais je ne crois pas qu'il y ait d'autres possibilités. J'ai écrit ce qui précède sans me vérifier, s'il y a des erreurs je m'en excuse sincèrement... disons que j'ai les neurones et les doigts fatigués :)

Tisha
 
WRInaute accro
waouhhhhh!!!
Merci beaucoup de ton aide.

Par contre j'ai un peu de mal:
admettons que je cherche dans la chaîne suivante : [BALISE]Texte<span>Texte</span>Texte[/BALISE]
tout ce qui ce trouve entre [BALISE]...[/BALISE], mais qui ne doit pas contenir <span

Je dois faire cela ?:
Code:
preg_replace('`\[BALISE\](.+!(<span))\[/BALISE\]`iU', <div>$1</div>,$texte)

ps: la chaine ne doit donc pas être transformée..
seul ce genre de chaîne peu être acceptée: [BALISE]Texte[/BALISE]
 
WRInaute accro
arf !! j'ai essayé plusieurs possibilités, mais j'ai vraiment beaucoup de mal.

J'espère que tu aura le temps encore un peu pour moi, parce que je galère et j'en est vraiment besoin. :(
 
WRInaute discret
thierry8 a dit:
Code:
preg_replace('`\[BALISE\](.+!(<span))\[/BALISE\]`iU', <div>$1</div>,$texte)

ça me semble pas très loin... je dirais

Code:
preg_replace('`\[BALISE\]((?:.(?!span[\s>]))+)\[/BALISE\]`iU','<div>$1</div>',$texte)

pas certaine pour le ungreedy... j'ai pas trop le temps de vérifier :( Je serai de retour dans 5 heures si ça ne fonctionne pas. Mais je pense que ça roulera correctement.

Tisha
 
WRInaute accro
Ok, le tien fonctionne bien, mais po le mien..

Code:
preg_replace('`\[BALISE\]((?:.(?!span[\s>]))+)\[/BALISE\]`iU','<div>$1</div>',$texte)

Il faut nécessairement le ?: : je ne comprends pas trop ce que ça signifie...(pour indiquer l'assertion ?)

ensuite tu as : .(?!span

et également : [\s>]

si tu pouvais me dire en détails à quoi cela correspond et sert :? je débute et j'avoue que j'ai un peu de mal là..

En tout cas je te remercie vraiment, car j'en avait vraiment besoin !!!
maintenant j'espère pouvoir comprendre ce dont j'utilise. :? :?

EDIT: j'ai également essayé ceci qui fonctionne:
echo
Code:
preg_replace('`\[BALISE\]((.(?!span\>))+)\[/BALISE\]`iU','<div>$1</div>', '[BALISE]Texte<span>Texte</span>Texte[/BALISE]')
 
WRInaute discret
thierry8 a dit:
Ok, le tien fonctionne bien, mais po le mien..
c'est déjà ça 8) elle est où ta regex? au fait pourquoi le salon htaccess/rewrite???

thierry8 a dit:
Code:
preg_replace('`\[BALISE\]((?:.(?!span[\s>]))+)\[/BALISE\]`iU','<div>$1</div>',$texte)
la fille était sur la fin de son heure du midi entre 2 cours, elle a donc fait les coins très ronds :oops:

thierry8 a dit:
Il faut nécessairement le ?: : je ne comprends pas trop ce que ça signifie...(pour indiquer l'assertion ?)
un masque se caractérise par les parenthèses, s'il y a ?: immédiatement après l'ouverture de parenthèse, alors le masque est non capturant, si tu préfères il n'engendre pas un $2 dans ce cas. une habitude que j'ai car preg_match_all est ma fonction favorite et moins il y a de masque capturant et + la fonction est rapide et consomme moins de mémoire.

thierry8 a dit:
ensuite tu as : .(?!span

et également : [\s>]
mouais, j'ai honte :oops: :oops: :oops:
le . représente 1 caractère et le (?!span[\s>]) veut dire que ce caractère ne doit pas avoir span\s ou span> à la suite. les coins sont ronds là, parceque ça tiendra pas la route sur la chaîne "[BALISE]qu'elle classe de span ai-je besoin[/BALISE]".

en fait, la fille avait eu une subite crainte d'une chaine dans le genre "[BALISE]<span class='bibi'>Texte</span> Texte[/BALISE]" :lol:

thierry8 a dit:
EDIT: j'ai également essayé ceci qui fonctionne:
Code:
preg_replace('`\[BALISE\]((.(?!span\>))+)\[/BALISE\]`iU','<div>$1</div>', '[BALISE]Texte<span>Texte</span>Texte[/BALISE]')
si span n'a jamais d'attribut(s) dans le genre <span class="bibi">, alors ce sera bon. mais pour ton questionnement initial, c'est à dire nier le bout de chaine <span alors ce serait:

Code:
  $texte="[BALISE]Texte <span>Texte</span> Texte[/BALISE]
          [BALISE]Texte Texte Texte[/BALISE]
          [BALISE]Texte Texte Texte[/BALISE]
          [BALISE]<span>Texte</span> Texte Texte[/BALISE]
          [BALISE]Texte <b>Texte</b> Texte[/BALISE]
          [BALISE]qu'elle classe de span ai-je besoin[/BALISE]
          [BALISE]<span class='bibi'>Texte</span> Texte[/BALISE]";
  echo htmlentities(preg_replace('`(?>\[BALISE\])((?:(?!<span).)+)(?>\[/BALISE\])`iU','<div>\\1</div>',$texte));
  /*
   (?>\[BALISE\])   => ancrage à gauche sur [BALISE]
   (                => masque capturant $1
   (?:              => masque non capturant
   (?!<span)        => ne doit pas avoir <span
   .)+              => répéter le masque non capturant 1 fois et +
   )                => fin du masque capturant
   (?>\[/BALISE\])  => ancrage à droite sur [/BALISE]
  */

et là la fille a testé et ça affiche
Code:
[BALISE]Texte <span>Texte</span> Texte[/BALISE] <div>Texte Texte Texte</div>  <div>Texte Texte Texte</div>  [BALISE]<span>Texte</span> Texte Texte[/BALISE] <div>Texte <b>Texte</b> Texte</div>  <div>qu'elle classe de span ai-je besoin</div>  [BALISE]<span class='bibi'>Texte</span> Texte[/BALISE]

as-tu pensé à la regex '`\[BALISE\]([^<]*?)\[/BALISE\]`i' ou bien si les éléments html sont autorisés à l'execption de span?


Tisha
 
WRInaute accro
Tisha a dit:
thierry8 a dit:
Ok, le tien fonctionne bien, mais po le mien..
c'est déjà ça 8) elle est où ta regex? au fait pourquoi le salon htaccess/rewrite???
La regex était celle indiquée au dessus.
Le salon...euh...une habitude..quand c'est sur les expressions régulières je post ici automatiquement...c'est vrai que ce n'est pas en rapport :oops:

Tisha a dit:
thierry8 a dit:
Code:
preg_replace('`\[BALISE\]((?:.(?!span[\s>]))+)\[/BALISE\]`iU','<div>$1</div>',$texte)
la fille était sur la fin de son heure du midi entre 2 cours, elle a donc fait les coins très ronds :oops:

thierry8 a dit:
Il faut nécessairement le ?: : je ne comprends pas trop ce que ça signifie...(pour indiquer l'assertion ?)
un masque se caractérise par les parenthèses, s'il y a ?: immédiatement après l'ouverture de parenthèse, alors le masque est non capturant, si tu préfères il n'engendre pas un $2 dans ce cas. une habitude que j'ai car preg_match_all est ma fonction favorite et moins il y a de masque capturant et + la fonction est rapide et consomme moins de mémoire.

thierry8 a dit:
ensuite tu as : .(?!span

et également : [\s>]
mouais, j'ai honte :oops: :oops: :oops:
le . représente 1 caractère et le (?!span[\s>]) veut dire que ce caractère ne doit pas avoir span\s ou span> à la suite. les coins sont ronds là, parceque ça tiendra pas la route sur la chaîne "[BALISE]qu'elle classe de span ai-je besoin[/BALISE]".
Merci je vais voir ça. Ces informations sont très utiles.

Tisha a dit:
en fait, la fille avait eu une subite crainte d'une chaine dans le genre "[BALISE]<span class='bibi'>Texte</span> Texte[/BALISE]" :lol:
En fait c'est pour ça que j'ai mis span> (la balise fermante...ainsi dedans jamais d'attributs)

Tisha a dit:
thierry8 a dit:
EDIT: j'ai également essayé ceci qui fonctionne:
Code:
preg_replace('`\[BALISE\]((.(?!span\>))+)\[/BALISE\]`iU','<div>$1</div>', '[BALISE]Texte<span>Texte</span>Texte[/BALISE]')
si span n'a jamais d'attribut(s) dans le genre <span class="bibi">, alors ce sera bon. mais pour ton questionnement initial, c'est à dire nier le bout de chaine <span alors ce serait:

Code:
  $texte="[BALISE]Texte <span>Texte</span> Texte[/BALISE]
          [BALISE]Texte Texte Texte[/BALISE]
          [BALISE]Texte Texte Texte[/BALISE]
          [BALISE]<span>Texte</span> Texte Texte[/BALISE]
          [BALISE]Texte <b>Texte</b> Texte[/BALISE]
          [BALISE]qu'elle classe de span ai-je besoin[/BALISE]
          [BALISE]<span class='bibi'>Texte</span> Texte[/BALISE]";
  echo htmlentities(preg_replace('`(?>\[BALISE\])((?:(?!<span).)+)(?>\[/BALISE\])`iU','<div>\\1</div>',$texte));
  /*
   (?>\[BALISE\])   => ancrage à gauche sur [BALISE]
   (                => masque capturant $1
   (?:              => masque non capturant
   (?!<span)        => ne doit pas avoir <span
   .)+              => répéter le masque non capturant 1 fois et +
   )                => fin du masque capturant
   (?>\[/BALISE\])  => ancrage à droite sur [/BALISE]
  */

et là la fille a testé et ça affiche
Code:
[BALISE]Texte <span>Texte</span> Texte[/BALISE] <div>Texte Texte Texte</div>  <div>Texte Texte Texte</div>  [BALISE]<span>Texte</span> Texte Texte[/BALISE] <div>Texte <b>Texte</b> Texte</div>  <div>qu'elle classe de span ai-je besoin</div>  [BALISE]<span class='bibi'>Texte</span> Texte[/BALISE]
Merci.
Mais :? je ne comprend pas :

(?>\[BALISE\]) => ancrage à gauche sur [BALISE]
(?>\[/BALISE\]) => ancrage à droite sur [/BALISE]

Et pourquoi avoir inversé le "." avec le span ? (en haut tu avais .(?!span>) )

Tisha a dit:
as-tu pensé à la regex '`\[BALISE\]([^<]*?)\[/BALISE\]`i' ou bien si les éléments html sont autorisés à l'execption de span?
Oui je m'en sert à certains endroits, mais à d'autres je ne peux pas car il n'y a que certaines balises qui ne sont pas autorisées.

Je vais essayer tout ça dans la journée.
Merci du coup de pouce énorme à la fille :wink:
 
WRInaute accro
Un grand merci à toi Tisha !

Ca fonctionne à merveille...
Deux trois trucs que je ne maîtrise pas encore, mais ça ne saurait tarder.
En revanche si tu pouvais encore me renseigner sur un point: le U
UNGREEDY, je ne sais pas exactement à quoi cela correspond.

J'ai trouvé cette définition, mais :? :? :?
U
(PCRE_UNGREEDY)
: Cette option inverse la tendance à la gourmandise des expressions régulières. Vous pouvez aussi inverser cette tendance au coup par coup avec un ?. De même, si cette option est activée, le ? rendra gourmand une séquence. Cette option n'est pas compatible avec Perl. Elle peut aussi être mise dans le masque avec l'option
 
WRInaute discret
La page sur laquelle tu as extrait la définition et sa soeur m'ont laissé plus 1 fois sur mon appétit :( Pourtant toute l'information nécessaire sur PCRE s'y trouve.

Pour ta question, le texte est exact: c'est à dire que le mode "pas glouton" sera satisfait de l'hypothèse la + proche. Dans ton cas, il ne dépassera pas le [/BALISE].

rien de tel qu'un p'tit exemple:

Code:
  $texte='[BALISE]texte[/BALISE]
          [BALISE]text[/BALISE]
          [BALISE]texte <span>texte</span>[/BALISE]
          [BALISE]texte texte[/BALISE]
          [BALISE]texte[/BALISE]
          [BALISE][/BALISE]';
          
  echo htmlentities(preg_replace('`\[BALISE\][^<]*\[/BALISE\]`i','*',$texte));
  echo '<hr>';
  echo htmlentities(preg_replace('`\[BALISE\][^<]*\[/BALISE\]`iU','*',$texte));

tu verras en mode normal, la recherche aura dépassé tout les [/BALISE] pour trouver une seule hypothèse. Puisqu'il n'y a que 2 *, 1 au début et 1 à la fin. En soi, c'est aussi exact car il n'y a qu'un bloc [BALISE][/BALISE] contenant un span.

alors qu'en ungreedy, tu auras 2* au début car 2 blocs [BALISE][/BALISE] avant celui contenant le span et 3* à la fin car 3 blocs [BALISE][/BALISE] après celui contenant le span.

Tisha
 
WRInaute accro
Ok, merci beaucoup encore une fois !!!!
Il est vrai que rien ne vaut un bon exemple !

Je te remercie pour toute ton aide. :wink:
 
Discussions similaires
Haut