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 :

Regex mots-clés : isoler les sous-chaînes [PHP 7]


Sujet :

Langage PHP

  1. #1
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut Regex mots-clés : isoler les sous-chaînes
    Bonjour,

    Je suis en train d'écrire un script PHP pour isoler dans une chaîne de caractères les mots-clés selon 3 critères :
    • mots encadrés par guillemets doubles
    • mots encadrés par guillemets simples
    • mots non encadrés


    Ainsi, je souhaiterais que les mots-clés saisis dans le champ texte soit traités comme dans l'exemple ci-dessous :

    Champ texte de saisie des mots-clés :
    "Green arrow" Spider-man Groot "Wonder woman"
    Résultat attendu :
    Green arrow
    Spider-man
    Groot
    Wonder woman
    Or, actuellement, un résultat n'est obtenu que par regex sur tous les mots sans tenir compte des guillemets. Il est le suivant :
    Array
    (
    [0] => Array
    (
    [0] => "Green
    [1] => arrow"
    [2] => Spider-man
    [3] => Groot
    [4] => "Wonder
    [5] => woman"
    )

    [1] => Array
    (
    [0] =>
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    )

    [2] => Array
    (
    [0] =>
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    )

    )
    Si je retire la partie de regex concernant tous les mots "unquoted" alors je n'obtiens qu'un résultat vide. Ce qui veut dire que mes regex sur simples et doubles quotes ne fonctionne pas du tout :
    Array
    (
    [0] => Array
    (
    )

    [1] => Array
    (
    )

    [2] => Array
    (
    )

    )

    Voici maintenant le code PHP que j'ai utilisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    $tempArray = "";
     
    // Putting to the array :
    // - double-quoted substrings
    // - single-quoted substrings
    // - unquoted substrings
    $regex_dbquotes = '"(.+)"';
    $regex_quotes = '\'(.+)\'';
    $regex_unquoted = '[^ ].\S*';                                       // Any non-whitespace character
     
    $regex = '/'.$regex_dbquotes.'|'.$regex_quotes.'|'.$regex_unquoted.'/';
     
    preg_match_all($regex, $this->searchString, $tempArray, PREG_PATTERN_ORDER);
    Comment corriger mes formules regex pour obtenir le résultat recherché ?

  2. #2
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut
    Je viens de comprendre mon erreur. En fait, je transforme toujours les chaînes de caractères issues de formulaires en entités HTML.
    Il me fallait donc appliquer mes regex sur " et ' au lieu de " et '.

    J'ai modifié les variables regex comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    $regex_dbquotes = '(").*?(")';
    $regex_quotes = '(').*?(')';
    $regex_unquoted = '(?!\W+"\b)\b[a-zA-Z0-9-_]+\b(?!\W+"\b)';   // Any word not starting with " and '
     
    $regex = '/'.$regex_dbquotes.'|'.$regex_quotes.'|'.$regex_unquoted.'/';
    D'où la chaîne regex suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    /(").*?(")|(').*?(')|(?!\W+"\b)\b[a-zA-Z0-9-_]+\b(?!\W+"\b)/
    Ce qui me donne le résultat suivant :
    Array
    (
    [0] => Array
    (
    [0] => "Green arrow"
    [1] => Spider-man
    [2] => Groot
    [3] => 'Wonder woman'
    )

    [1] => Array
    (
    [0] => "
    [1] =>
    [2] =>
    [3] =>
    )

    [2] => Array
    (
    [0] => "
    [1] =>
    [2] =>
    [3] =>
    )

    [3] => Array
    (
    [0] =>
    [1] =>
    [2] =>
    [3] => '
    )

    [4] => Array
    (
    [0] =>
    [1] =>
    [2] =>
    [3] => '
    )

    )

  3. #3
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut
    Le problème n'est pas entièrement réglé pour autant car j'obtiens un certain nombre de sous-tableaux alors qu'un seul serait plus pratique. Bien sûr, ça peut tout à fait fonctionner si je n'utilise que le 1er sous-tableau. Néanmoins, je ne trouve pas cela très propre.

    Donc j'ai besoin de votre pour m'aider à affiner ma regex pour :
    • ne pas inclure les " et &#039 ; dans les sous-chaînes à enregistrer,
    • ne pas continuer les sous-tableaux car il détecte ensuite individuellement chaque " et &#039 ;

  4. #4
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut
    N'arrivant toujours pas à régler ce problème de sous-tableaux, j'ai dû passer par une conversion des entités HTML en caractères correspondants avant de traiter par regex. Du coup, j'ai aussi recréé mes regex en conséquence.
    J'ai donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    // Decoding the html entities : " and '
    $decodedSearchString = html_entity_decode ($this->searchString, ENT_QUOTES);
     
    $regex_dbquotes = '(?<=").+(?=")';                                      // Any word(s) enclosed by double quotes
    $regex_quotes = '(?<=\').+(?=\')';                                      // Any word(sà enclosed by single quotes
    $regex_unquoted = '(?<!"|\')\b[a-zA-Z0-9-_]+\b(?!"|\')';                // Any word not starting with " and '
    $regex = '/'.$regex_dbquotes.'|'.$regex_quotes.'|'.$regex_unquoted.'/';
     
    preg_match_all($regex, $decodedSearchString, $tempArray, PREG_PATTERN_ORDER);
     
    // Displaying the values of the array
    print_r($tempArray);
    Saisie dans le champ texte de la barre de recherche :
    "David Bowie" Spider-man Groot 'Wonder Woman'
    Ce code me renvoie :
    Array
    (
    [0] => Array
    (
    [0] => David Bowie
    [1] => Spider-man
    [2] => Groot
    [3] => Wonder Woman
    )

    )

  5. #5
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 888
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 888
    Points : 6 632
    Points
    6 632
    Par défaut
    Le problème c'est que c'est encore faux car si tu as deux passages entre quotes (avec les mêmes quotes) sur la même ligne ça ne marchera pas. D'autre part on peut faire plus élégant en utilisant des groupes de captures et un branch reset (un groupe avec plusieurs alternatives au sein duquel les groupes de capture sont les mêmes dans chaque alternative):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $str = '"David Bowie" Spider-man "Michèle Torr" Groot \'Wonder Woman\'';
     
    $pattern = '~ (?|  \' ( [^\']* ) \'  |  " ( [^"]* ) " |  ( \S+ ) ) ~xu';
     
    preg_match_all($pattern, $str, $matches);
     
    print_r($matches[1]);
    NB: quoi que tu fasses, preg_match_all renvoie toujours un tableau multi-dimensionnel. L'option PREG_PATTERN_ORDER est l'option par défaut, il est inutile de l'indiquer.

  6. #6
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut
    Merci beaucoup CosmoKnacki !
    Effectivement ça marche.

    L'inconvénient par contre c'est que ça me laisse les " et ' encadrant les groupes de mot.

  7. #7
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 888
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 888
    Points : 6 632
    Points
    6 632
    Par défaut
    Non, et c'est tout l'intérêt des groupes de capture! Le résultat sans les quotes est dans $matches[1] (groupe de capture 1) pas dans $matches[0] (correspondance complète).

  8. #8
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut
    Ah oui, j'avais oublié que j'appliquais un autre traitement sur le tableau en l'appelant par l'indice 0.
    Je te remercie beaucoup, c'est nickel !

    Enfin, les regex élégants sont quand même vachement plus imbuvables que les regex de base (s'il y en a) mais content de voir que des experts de ces sujets tendent la main.

  9. #9
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 888
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 888
    Points : 6 632
    Points
    6 632
    Par défaut
    Ou alors on change carrément de méthode et on utilise preg_split avec l'option PREG_SPLIT_DELIM_CAPTURE:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $str = '"David Bowie" Spider-man "Michèle Torr" Groot \'Wonder Woman\'';
     
    $pattern = '~ \' ( [^\']* ) \'  |  " ( [^"]* ) " | \s+ ~xu';
     
    print_r(preg_split($pattern, $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY));
    comme ça, pas de tableau multi-dimensionnel.

  10. #10
    Invité
    Invité(e)
    Par défaut
    @CosmoKnacki

    "Michelle Torr" ????

    [EDIT] J'ai aussi tenté l'exercice hier...
    J'en étais arrivé à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $regex = '#(?:(?:^|["])([^ ][^"]*[^ ])(?:["]|$))|(?:(?:^|[\'])([^ ][^\']*[^ ])(?:[\']|$))|(?:(?:^|[ ])([^\'"][^\'"]*[^\'"])(?:[ ]|$))#Ui';
    preg_match_all($regex, $chaine, $matches, PREG_PATTERN_ORDER);
    $results = [];
    for($i=1;$i<=3;$i++)
    {
    	foreach( array_unique($matches[$i]) as $match )
    	{
    		if( !empty($match) )
    		{
    			$results[] = $match;
    		}
    	}
    }
    var_dump( $results );
    J'obtiens "presque" le bon résultat (reste le " devant David), mais j'avoue que ta regex... me laisse pantois.
    Dernière modification par Invité ; 13/04/2020 à 10h25.

  11. #11
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 888
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 888
    Points : 6 632
    Points
    6 632
    Par défaut
    Oui, Michèle Torr, fille d'Odin a parfaitement sa place parmi les héros de comics (le seul intrus dans cette liste étant David Bowie).

    Pour ce qui est du " récalcitrant, tu dois inverser tes groupes au début de chaque branche:
    • (?:^|") => (?:"|^)
    • (?:^|') => (?:'|^)
    • (?:^|[ ]) => (?:[ ]|^)

    car sinon au début de la chaîne l'ancre ^ gagnera toujours.

  12. #12
    Invité
    Invité(e)
    Par défaut
    Au contraire !
    Bowie est "THE HERO" !




    Citation Envoyé par CosmoKnacki Voir le message
    car sinon au début de la chaîne l'ancre ^ gagnera toujours.
    Bien vu


    [EDIT] "Michelle Torr, fille d'Odin"

  13. #13
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 888
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 888
    Points : 6 632
    Points
    6 632
    Par défaut
    Citation Envoyé par jreaux62 Voir le message
    Au contraire !
    Bowie est "THE HERO" !
    Autant pour moi! On peut d'ailleurs le voir en tenue de combat lors d'un concert en 1973.

  14. #14
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Août 2017
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 45
    Points : 17
    Points
    17
    Par défaut
    Bien ouéj vous deux !

    D'ailleurs, Michelle est Torr-ide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 24/09/2014, 20h55
  2. Tags / mots clés sur les pages ?
    Par faldren dans le forum Général Conception Web
    Réponses: 1
    Dernier message: 25/05/2010, 09h17
  3. [RegEx] Isoler une sous-chaîne ayant plusieurs délimitateurs possibles
    Par Aoyama dans le forum Langage
    Réponses: 11
    Dernier message: 23/04/2009, 10h07

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