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

Python Discussion :

Parser fichier texte


Sujet :

Python

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut Parser fichier texte
    Bonjour,

    J'ai un fichier avec des lignes sous cette forme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    field1 field2 field3 " field 4 "
    Je voudrais par ligne, récupérer chaque champ dans un tableau, sachant que :
    - une ligne peut être vide ou contenir des espaces ou/et des tabulations
    - chaque champ est séparé par un ou plusieurs caractères espace ou/et tabulation
    - si un champ est entre guillemet, les caractère espace ou tabulation ne doivent pas être supprimés
    - si un champ est entre guillemet, les guillemets doivent être supprimés. ex : "salut toi" => salut toi.
    - si un guillemet est ouvert mais n'est pas refermé, la ligne ne doit pas être prise en compte (et un message d'erreur doit être généré)
    - si le caractère guillemet est précédé du caractère '\', il doit être géré comme un caractère normal et le '\' doit être supprimé. ex : "salut \"toi " => salut "toi.

    Comment faut-il faire pour gérer cela ?... la principale problématique étant de gérer les guillemets et les multiple caractères de séparation de champ (espace et tabulation)

    Mon code actuel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    with open('file.ini', "r") as textfile:
      for line in textfile:
        line = line.strip() # suppression retour de ligne
        if not line:
          continue # ligne vide
     
        print(line)
     
        fields = line.split(' ')
        if not fields:
          continue # pas de champ
     
        for field in fields:
          print("\"" + field + "\"")

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Ci-joint, un fichier de test qui doit renvoyer le tableau suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    fileContents = [
      ["fieldA1", "fieldA2", "  field  A3 ", "field", "A4"],
      ["fieldB1", " field \" B2", "  field  A3 ", "field\"B3"],
      ["fieldC1", "fieldC2"]
    ];
    Fichiers attachés Fichiers attachés

  3. #3
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Salut,

    Est-ce que tu as vérifié si le module csv pouvait faire cela (j'en doute mais on ne sait jamais) ?

    S'il ne peut pas alors effectivement il reste la solution de faire cela soi-même...

    Et fields = line.split(' ') ne me semble pas une bonne idée car comme tu l'as dis il peut y avoir un ou plusieurs espaces et/ou tabulations... Et il peut y en avoir même à l'intérieur des guillemets or cette instruction ne fera pas la différence...

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 984
    Points
    30 984
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Beginner. Voir le message
    Est-ce que tu as vérifié si le module csv pouvait faire cela (j'en doute mais on ne sait jamais) ?
    Il sait gérer pas mal de choses. Déjà les guillemets il gère. De même s'il y a plusieurs lignes avec des '\n' dans un champ entre guillemets il sait gérer. Le backslash qui protège il gère aussi.
    Le seul truc dont je ne sait rien, c'est s'il sait gérer des champs séparés par différents caractères (parfois espace, parfois tabulation, parfois plusieurs). Mais bon, quand on en arrive à avoir ce format d'entrée peut-être est-il judicieux d'envisager de le retourner dans la tronche de l'émetteur en lui disant d'arrêter de déconner...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 821
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 821
    Points : 979
    Points
    979
    Par défaut
    Merci, je vais zieuté du coté du module CSV

    Citation Envoyé par Sve@r Voir le message
    Mais bon, quand on en arrive à avoir ce format d'entrée peut-être est-il judicieux d'envisager de le retourner dans la tronche de l'émetteur en lui disant d'arrêter de déconner...
    ... lorsque l'on crée un fichier texte, il arrive souvent que l'on veuille aligner certains éléments entre différentes lignes pour que ça soit plus lisible... et selon l'editeur de texte utilisé, lorsque l'on appuie sur la touche tab, on a des fois des tab et des fois des espaces... donc si le fichier est édité par plusieurs personnes qui utilisent des éditeurs de texte différents, on peut facilement avoir des espace et des tabulations mélangés

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 984
    Points
    30 984
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par boboss123 Voir le message
    ... lorsque l'on crée un fichier texte, il arrive souvent que l'on veuille aligner certains éléments entre différentes lignes pour que ça soit plus lisible...
    Ah ben il faut faire parfois des choix. Avoir un fichier plus lisible... ou avoir un fichier plus adapté à un traitement automatisé. Perso je sais ce que j'ai choisi...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Merci Sve@r pour les infos...
    Citation Envoyé par Sve@r Voir le message
    Le seul truc dont je ne sait rien, c'est s'il sait gérer des champs séparés par différents caractères (parfois espace, parfois tabulation, parfois plusieurs).
    Effectivement... C'est peut-être possible si il nous permet de définir le séparateur via une regex...

    J'ai essayé avec libreOffice et on peut choisir plusieurs séparateurs différents mais du coup on se retrouve avec des champs vides et il ne s'en sort pas bien avec le backslash...

    De toute façon je doute que certaines conditions comme celle ci-dessous soient prises en compte :

    si un guillemet est ouvert mais n'est pas refermé, la ligne ne doit pas être prise en compte (et un message d'erreur doit être généré)
    Citation Envoyé par boboss123 Voir le message
    Ci-joint, un fichier de test qui doit renvoyer le tableau suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    fileContents = [
      ["fieldA1", "fieldA2", "  field  A3 ", "field", "A4"],
      ["fieldB1", " field \" B2", "  field  A3 ", "field\"B3"],
      ["fieldC1", "fieldC2"]
    ];
    Il y a quelques soucis ou j'ai mal compris, voici le contenu du fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
              fieldA1            fieldA2 "  field  A3 "    field A4
     
     
    fieldB1  " field \" B2" field\"B3       
     fieldC1 fieldC2
    Je ne vois pas d'où vient cet élément " field A3 ", il n'est pas présent à la ligne 5 du fichier...

    Sinon ici on voit le backslash mais il n'est pas censé être présent d’après tes conditions, n'est-ce pas ?

  8. #8
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    avec des regex, c'est pas forcément ce qu'il y a de plus propre à ce stade mais ça se fait bien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import re
     
    f1, f2 = [], [
      ["fieldA1", "fieldA2", "  field  A3 ", "field", "A4"],
      ["fieldB1", r" field \" B2", r"field\"B3"],
      ["fieldC1", "fieldC2"]
    ]
     
    with open('test.txt', 'r') as f:
        for n,l in enumerate(f):
            line = l.rstrip()
            if not re.match(r'^\s*$', line):
                if len(re.findall(r'(?<=[^\\])"', line))%2:
                    print(f'Erreur ligne {n}: {line}')
                    continue
                f1.append([i if i else j for i,j in re.findall(r'"((?:\\"|.)+?)"|([^\s]+)', line)])
     
    print(f1 == f2)
    c'est vrai que la contrainte de poubelliser la ligne si les guillemets ne sont pas appairés ça complique un peu les choses, mais finalement on peut s'en sortir en vérifiant simplement que le nombre de guillemets est multiple de deux

    et le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Erreur ligne 6: tagada "tsoin tsoin
    Erreur ligne 7: pouet "coin" taga \"  " prout
    True
    note que j'ai modifié le fichier de tests, un champs de la liste fournie contenait indûment " field A3 " (comme l'a fait remarquer Beginner.), et il manquait un testcase pour une ligne avec des guillemets non-appairés, j'en ai rajouté deux en fin de fichier qui notifient donc une erreur

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 984
    Points
    30 984
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par BufferBob Voir le message
    on peut s'en sortir en vérifiant simplement que le nombre de guillemets est multiple de deux
    "Hello \" World"
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    "Hello \" World"
    normalement c'est valide ça, le programme doit s'en sortir, il y a bien 1 paire de guillemets et un guillemet tout seul au milieu échappé donc ignoré (c'est matché via la regex)

  11. #11
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Autre solution mais plus lourde : pyParsing
    Il permet de gérer de façon transparente les espaces et les tabulations dans son analyse de grammaire.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  12. #12
    Membre actif Avatar de olivier1969
    Homme Profil pro
    Assistant aux utilisateurs
    Inscrit en
    Novembre 2013
    Messages
    151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Assistant aux utilisateurs
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Novembre 2013
    Messages : 151
    Points : 208
    Points
    208
    Par défaut
    Hello, ceci devrai faire l'affaire .... pour chaque ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    sp = '  ch1    "  ch2 \"  ch3  'nb = sp.count('"')
    if nb % 2 != 1 :
        tmp = re.sub(r'"', ' ', sp)
        tmp1 = re.sub(r'\t+', ' ', tmp)
        tmp2 = re.sub(r'^\s+|\s+$', '', tmp1)
        res = re.sub(r'\s+',' ', tmp2).split(' ')
        print (res)
    else :
        print('error')

Discussions similaires

  1. Parser fichier texte
    Par titou31000 dans le forum Langage
    Réponses: 5
    Dernier message: 19/06/2013, 11h05
  2. Parser fichier texte : 1 ligne --> 800 mo!
    Par bigbobby64 dans le forum C#
    Réponses: 3
    Dernier message: 27/11/2012, 09h07
  3. Parser un petit fichier texte
    Par viscere dans le forum Format d'échange (XML, JSON...)
    Réponses: 5
    Dernier message: 26/04/2006, 09h59
  4. parser fichier texte pour avoir un doc html !!
    Par avogadro dans le forum Débuter
    Réponses: 4
    Dernier message: 30/03/2006, 16h12
  5. Parser de fichier textes >> Logs Apache
    Par gregb34 dans le forum Langage
    Réponses: 2
    Dernier message: 17/02/2006, 18h34

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