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 :

une Regex multiligne [RegEx]


Sujet :

Langage PHP

  1. #1
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut une Regex multiligne
    Bonjour,

    J'ai un fichier de rapport avec pleins de ligne. Dans ce fichier, il y a une section que je voudrais récupéré :

    [...]

    Switch Ports Model SW Version SW Image
    ------ ----- ----- ---------- ----------
    * 1 52 WS-C2960S-48FPS-L 12.2(55)SE5 C2960S-UNIVERSALK9-M
    2 52 WS-C2960S-48FPS-L 12.2(55)SE5 C2960S-UNIVERSALK9-M

    [...]
    J'aimerai récupéré ce tableau pour ensuite récupéré les information des différentes colonnes (mais c'est un autre sujet).

    Sur internet, j'ai trouvé un exemple qui fonctionne :

    truck
    zDoug
    Doug's house
    (123) 456-7890
    Edoug@doug.com
    30
    61234.56
    8/10/2003

    vehicle
    eRob
    Rob's house
    (987) 654-3210
    Frob@rob.com
    La regex associé récupère à partir du mot "truck" toutes les lignes jusqu'au prochain saut de ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (?m)^truck(?:(?:\r\n|[\r\n]).+$)*
    Je ne comprend pas toute la syntaxe de ce regex, donc j'ai du mal à l'adapter à mon besoin.

    Pourriez-vous m'aidé ?

    En vous remerciant d'avance.

  2. #2
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    Finalement j'ai trouvé !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (?m)^Switch.*Ports.*Model.*SW Version.*(?:(?:\r\n|[\r\n]).+$)*

  3. #3
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    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 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Peut-être que ça marche ou que ça semble marcher mais: Pourquoi cette solution est vilaine?:
    • Elle t'oblige à lire et à stocker en mémoire l'intégralité du fichier. Donc tu liras des parties du fichier pour rien (sauf si ton bloc est à la toute fin) et tu encombreras la mémoire pour rien aussi avec les autres parties qui ne sont pas ton bloc.
    • La pattern que tu as adaptée est aussi assez vilaine à la base (?m)^truck(?:(?:\r\n|[\r\n]).+$)*:
      • On peut utiliser \R (qui est un alias pouvant matcher plusieurs type de saut de lignes) plutôt que (?:\r\n|[\r\n]) ou à la limite \r?\n (pour décrire uniquement les sauts de lignes UNIX ou Windows. \r n'est plus utilisé depuis OS9, on peut maintenant le ranger dans les sauts de lignes exotiques). Ce n'est pas très grave, mais c'est bien plus pratique d'écrire: (?:\R.+$)* ou (?:\r?\n.+$)*
      • Le groupe (?:(?:\r\n|[\r\n]).+$)* est optionnel (de par le quantificateur *), ce qui signifie que s'il n'est pas présent, la pattern équivaut à (?m)^truck (note que l'ancre $ n'est alors plus présente), ce qui ne permet pas de savoir si "truck" est une entête de block, le début d'une entête (car elle matche la chaîne: "truck machin bidule") ou autre.
      • Rien ne prouve que la ligne "truck" est une entête de block puisque la pattern ne vérifie pas que la ligne précédente n'est pas vide/blanche ou qu'on est au tout début de la chaîne.

      En bref, si utiliser cette pattern avait été une bonne idée, il aurait fallu l'écrire plutôt dans ce goût la: /^(?:\A|\h*\R)\Ktruck(?:\R\h*\S.*)*+$/m (Pas la peine d'utiliser le switch inline (?m), tu peux l'appliquer globalement sur la pattern et le placer après le délimiteur /. \A matche le début de la chaîne. \h est une caractère blanc horizontal. ^\h*\R une ligne blanche, et donc \h*\S.*$ est une ligne avec au moins un caractère non-blanc \S).
    • La sous pattern que tu as rajoutée Switch.*Ports.*Model.*SW Version est ce que l'on appelle une pattern "pathologique". Ce sobriquet est dû au fonctionnement du moteur de regex utilisé par PHP qui est un moteur à backtracking. Ce qui a pour conséquence de générer énormément de tests (le nombre croissant rapidement en fonction de la taille de la chaîne) avec une pattern comme a.*b.*c.*d pour une chaîne comme "axxxxxxxxxxbxxxxxxxxxxcxxxxxxxxxxxx". Voir catastrophic backtracking.
      Dans ton cas le problème peut être facilement évité puisque tu connais déjà l'entête recherchée. Donc inutile d'introduire de l'imprécision avec .* lorsque tu sais que les noms de champs sont séparés d'un espace ou d'une tabulation. Donc Switch\h+Model\h+SW Version sera beaucoup plus fiable car plus restrictif.


    Pour en revenir au premier point de la liste: à mon avis une approche itérative avec une lecture ligne par ligne de ton fichier (avec fgets ou stream_get_line) est bien plus élégante, plus robuste qu'une pattern approximative, et économe en mémoire (et éventuellement en accès disque). Rien ne garantie que le résultat sera plus rapide ou que le gain de mémoire sera significatif si tu manipules des petits fichiers, mais s'il s'agit de petits fichiers cela n'a aucune importance donc autant procéder de cette manière.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

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

Discussions similaires

  1. [RegEx] regex sur une chaine multilignes
    Par shinji7800 dans le forum Langage
    Réponses: 6
    Dernier message: 19/03/2017, 08h56
  2. [VB6] Découper un mot dans une textBox multiligne?
    Par bb62 dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 09/02/2006, 11h26
  3. [RegEx] php et javascript dans une regex
    Par grochenel dans le forum Langage
    Réponses: 7
    Dernier message: 06/12/2005, 22h21
  4. [RegEx] spliter par rapport a une regex en récuperant la regex
    Par Khrysby dans le forum Langage
    Réponses: 1
    Dernier message: 10/11/2005, 15h08
  5. [langage] Extraire un block dans une variable multiligne
    Par |DUCATI| DesMo dans le forum Langage
    Réponses: 9
    Dernier message: 11/02/2003, 14h56

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