Manipuler un fichier

LALO_5656 Messages postés 31 Statut Membre -  
mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   -

Bonjour à tous,

J'ai plus de 100 fichiers txt que je voudrais ouvrir un par un.

  • Dans chaque fichier ouvert je voudrais copier certaines chaines de caractères qui se trouvent sur des lignes différentes et les coller dans le fichier csv (rapport).
  • Dans tous mes fichiers, les données à copier se trouvent sur les mêmes lignes

Voila le code que j'ai essayé d'écrire mais qui marche pas:

import parse
with fichier as fichier:
    ligne = fichier.readlines()
    ligne10 = parse.parse("STRT.M {}                                 :START DEPTH", ligne[10])
    ligne16 = parse.parse("STCK.    {}                               :STACK", ligne[16])
import csv
header = ["Operateur", "Début rdc", "Fin rdc", "Type", "Prof"]
with open(rapport, "w") as csv_file:
    writer = csv.writer(csv_file, delimiter=",")
    writer.writerow(header)

Je suis vraiment débutant en python. Quelqu'un a une idée ? D'avance merci !

8 réponses

  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    Bonjour,

    Néanmoins sais-tu comment je peux coller cette information dans mon fichier csv au niveau de la colonne Prof ? 

    Je suppose que ce que tu veux reporter dans la colonne Prof est le résultat de m.group(1) ?

    Il faudrait spécifier comment tu remplis chaque colonne en fonction de la ligne lue. Ce que je te conseille, c'est de faire une liste de dictionnaires, tels que leur clé coïncident avec les noms de colonnes. Appelons dans ce qui suit entries la liste de dictionnaire et entry le dictionnaire courant.

    Ci-dessous un exemple de code qui devrait te débloquer :

    import csv, re
    from io import StringIO
    from pprint import pprint
    
    RE_STRT_M = re.compile("STRT\.M\s+(\w+)\s+:START DEPTH")
    RE_STCK = re.compile("STCK\.\s+(\w+)\s+:STACK")
    
    def make_dummy_input_file(i) -> StringIO:
        lines = [f"line{i}" for i in range(20)]
        lines[10] = f"STRT.M   plop{i}     :START DEPTH"
        lines[16] = f"STCK.    pouet{i}      :STACK"
        return StringIO("\n".join(lines))
    
    def extract_strt_m(s: str) -> str:
        m = RE_STRT_M.match(s)
        return m.group(1) if m else None
    
    def extract_stck(s: str) -> str:
        m = RE_STCK.match(s)
        return m.group(1) if m else None
    
    def extract_data(lines) -> dict:
        strt_m = extract_strt_m(lines[10])
        stck = extract_stck(lines[16])
        return {
            "strt_m" : strt_m,
            "stck"   : stck,
        }
    
    def entries_to_csv(entries: list, f_out, *cls, **kwargs) -> bool:
        if not entries:
            return False
        writer = csv.writer(f_out, *cls, **kwargs)
        keys = sorted(entries[0].keys())
        writer.writerow(keys)
        for entry in entries:
            writer.writerow([entry.get(k) for k in keys])
        return True
    
    def print_file(filename):
        with open(filename, "r") as f:
            print("".join(f.readlines()))
    
    def main():
        entries = list()
        for i in range(10):
            # Generate dummy data to parse
            input_data = make_dummy_input_file(i)
            #print("-" * 80)
            #print(input_data.getvalue())
    
            # Read the i-th file
            lines = input_data.readlines()
            entry = extract_data(lines)
            entry["index"] = i
            entries.append(entry)
    
        print("=" * 80)
        pprint(entries)
    
        filename_csv = "toto.csv"
        with open(filename_csv, "w") as f_out:
            entries_to_csv(entries, f_out)
    
        print("=" * 80)
        print_file(filename_csv)
    
    main()
    

    Il faut commencer par lire le main : je génère 10 StringIO (qui sont des chaînes qui se comportent comme des fichiers, donc on peut appliquer dessus readlines comme tu le fais avec des fichiers normaux) avec la fonction make_dummy_input_file. Tu peux décommenter les fonctions print pour voir que leur contenu est conforme à tes fichiers (donc, des données à extraire lignes 10 et 16). Les "fichiers" ont un contenu différent en fonction de leur index i (qui commence à 0). Par exemple le 9-ème "fichier" contient :

    line0
    line1
    line2
    line3
    line4
    line5
    line6
    line7
    line8
    line9
    STRT.M   plop8     :START DEPTH
    line11
    line12
    line13
    line14
    line15
    STCK.    pouet8      :STACK
    line17
    line18
    line19

    Ensuite, j'extrais de chacun de ces "fichiers" leurs données avec extract_data, qui en cascade appelle les fonctions permettant d'extraire les valeurs que tu veux récupérer. Selon la nature de ces données, note qu'il faudra peut-être adapté les expressions_régulières RE_*. Mais comme à ce stade, ce n'est pas spécifié, j'ai supposé que les valeurs à extraire étaient dans les deux cas un mot composé de caractères alphanumériques.

    Comme je ne sais pas comment tu veux reporter les valeurs extraites dans les colonnes, j'ai considéré que le fichier csv contenait une ligne par fichier, et trois colonnes (l'index du fichier i, et une colonne par valeur extraite).

    Une fois le code exécuté, on voit qu'on est parvenu à extraire les valeurs de nos 10 fichiers d'entrées :

    ================================================================================
    [{'index': 0, 'stck': 'pouet0', 'strt_m': 'plop0'},
     {'index': 1, 'stck': 'pouet1', 'strt_m': 'plop1'},
     {'index': 2, 'stck': 'pouet2', 'strt_m': 'plop2'},
     {'index': 3, 'stck': 'pouet3', 'strt_m': 'plop3'},
     {'index': 4, 'stck': 'pouet4', 'strt_m': 'plop4'},
     {'index': 5, 'stck': 'pouet5', 'strt_m': 'plop5'},
     {'index': 6, 'stck': 'pouet6', 'strt_m': 'plop6'},
     {'index': 7, 'stck': 'pouet7', 'strt_m': 'plop7'},
     {'index': 8, 'stck': 'pouet8', 'strt_m': 'plop8'},
     {'index': 9, 'stck': 'pouet9', 'strt_m': 'plop9'}]
    ================================================================================
    index,stck,strt_m
    0,pouet0,plop0
    1,pouet1,plop1
    2,pouet2,plop2
    3,pouet3,plop3
    4,pouet4,plop4
    5,pouet5,plop5
    6,pouet6,plop6
    7,pouet7,plop7
    8,pouet8,plop8
    9,pouet9,plop9

    Bonne chance

    1
  2. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    Bonjour,

    Peux-tu donner un exemple minimal de fichier d'entrée et de fichier de sortie ?

    Dans le premier extrait de code, si j'ai bien compris ce que tu veux faire, tu veux extraire des lignes 10 et 16 la chaîne de caractère située après STRT.M et STCK. ? Personnellement j'utiliserais le module re et une expression régulière.

    import re
    
    s = "STRT.M   pouet     :START DEPTH"
    r = re.compile("STRT.M\s+(\w+)\s+:START DEPTH")
    m = r.match(s)
    if m:
        print(m.group(1)) # Affiche "pouet"

    Et dans le second, comme header n'est pas défini je ne sais pas ce que tu veux faire.

    Bonne chance

    0
  3. LALO_5656 Messages postés 31 Statut Membre 2
     

    Bonsoir merci infiniment. Ça m'a beaucoup aidé. Néanmoins sais-tu comment je peux coller cette information dans mon fichier csv au niveau de la colonne Prof ? Encore merci

    0
  4. LALO_5656 Messages postés 31 Statut Membre 2
     

    Bonjour mamiemando, merci pour vos réactions.

    Désolé de vous déranger encore plus, mais je n'arrive vraiment pas à adapter le code à mes besoins. En clair, voici

    J'ai plus de cent fichiers numérotés ainsi :

    • I16T04-001
    • ...
    • I16T04-121

    Dans mon fichier de sortie, la première colonne comporte le nom du fichier ouvert.

    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    Bonjour,

    Je n'ai pas pu accéder au fichier de sortie (il faut une autorisation) mais j'ai pu voir le fichier d'entrée. Il serait beaucoup plus simple pour tout le monde que tu copies colle directement le contenu de tes fichiers dans tes message.

    I16T04-001

    #------------------------------------------------
    ~Version Information Section
    VERS.     2.0     :  CWLS Log Ascii Standard Version
    WRAP.  NO  :  One Line Per Depth
    #------------------------------------------------
    #------------------------------------------------
    ~Well Information Section
    #MNEM.UNIT        VALUE.NAME                     DESCRIPTION
    #------------------------------------------------
    STRT.M   6.70                                    :START DEPTH
    STOP.M   -0.80                                   :STOP DEPTH
    STEP.M   -0.10                                   :STEP
    NULL.    -999.25                                 :NULL VALUE
    COMP.    foat                                    :COMPAGNIE
    WELL.   TAMR                                     :FORAGE
    STCK.    GGWL_7800                               :STACK
    PHA.     1                                       :N° PHASE
    RUN.     2                                       :N° RUN
    CTRY.    NEANT                                   :PAYS
    PROV.    YAOUT                                   :PROVINCE
    FLD.     ARTO                                    :CHANTIER
    STKP.    DECENTERED                              :POS. DU STACK
    LONG.M                                           :LONGITUDE
    LAT.M                                            :LATITUDE
    EGL.M                                            :ALTITUDE
    CSYS.                                            :SYS. COORDO.
    DREF.    CASING                                  :PROF. DE REF.
    BS.MM    76.2                                    :DIAM. THEORIQUE
    TDD.M                                            :PROF. FOREUR
    TDL.M                                            :PROF. DIAG.
    DFT.     BENTONITE                               :TYPE DE FLUIDE
    MSS.     MUD PIT                                 :ORIGINE FLUIDE
    DFD.GM3                                          :DENSITE
    DFV.S                                            :VISCOSITE
    DFLS.    NON                                     :PERTE
    DFL.M3                                           :VOLUME
    DFLV.M                                           :NIVEAU
    DATE.    18/08/22                                :DATE DE DEBUT
    END.     18/08/22                                :DATE DE FIN
    DLAB.    18/08/22                                :STK AU FOND
    DLAT.    18/08/22                                :STK EN SURFACE
    AUTO.    Log started jeudi, août 18 2022  21:55  :
    OPE.     samuel                                  :DIAGRAPHISTE
    SRVC.    TANOUT                                  :DIAG. COMP.
    UNIT.    1500                                    :N° BAIE
    COME.    OPEN HOLE                               :ENV. DE MESURE
    UWI.     0000     :UNIQUE WELL ID
    

    Ensuite il y a plusieurs choses à corriger dans le script que je t'ai donné :

    • Plus besoin de générer des fichiers d'exemples, on lit directement les vrais.
    • En python les listes sont indexées à partir de 0. Donc quand tu parles des lignes 10 et 16, il s'agit en python des éléments 9 et 15 dans la liste engendrée par f.readlines(). Une manière simple de déboguer et d'afficher la chaîne s traitée par extract_stck et extract_strt_m.
    • Il faut bien entendu adapter le main pour lire l'ensemble de tes fichiers. En admettant que le script toto.py et les fichiers d'entrées sont dans le même dossier :
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import csv, re, sys
    from io import StringIO
    from pprint import pprint
    
    RE_STRT_M = re.compile("STRT\.M\s+(\S+)\s+:START DEPTH")
    RE_STCK = re.compile("STCK\.\s+(\S+)\s+:STACK")
    
    def extract_strt_m(s: str) -> str:
        print(f"extract_strt_m({s})")
        m = RE_STRT_M.match(s)
        return m.group(1) if m else None
    
    def extract_stck(s: str) -> str:
        print(f"extract_stck({s})")
        m = RE_STCK.match(s)
        return m.group(1) if m else None
    
    def extract_data(lines) -> dict:
        strt_m = extract_strt_m(lines[9])
        stck = extract_stck(lines[15])
        return {
            "strt_m" : strt_m,
            "stck"   : stck,
        }
    
    def entries_to_csv(entries: list, f_out, *cls, **kwargs) -> bool:
        if not entries:
            return False
        writer = csv.writer(f_out, *cls, **kwargs)
        keys = sorted(entries[0].keys())
        writer.writerow(keys)
        for entry in entries:
            writer.writerow([entry.get(k) for k in keys])
        return True
    
    def print_file(filename):
        with open(filename, "r") as f:
            print("".join(f.readlines()))
    
    def main():
        entries = list()
        for filename in [
            f"I16T04-{i:03d}"
            for i in range(1, 122)
        ]:
            try:
                with open(filename, "r") as f:
                    lines = f.readlines()
                    entry = extract_data(lines)
                    entry["filename"] = filename
                    entries.append(entry)
                print(f"Processed {filename}")
            except Exception as e:
                print(f"Skipping {filename}: {e}", sys.stderr)
    
        filename_csv = "output.csv"
        with open(filename_csv, "w") as f_out:
            entries_to_csv(entries, f_out)
    
        print("=" * 80)
        print_file(filename_csv)
    
    main()
    • Les expressions rationnelles que j'ai donné précédemment font l'hypothèse que le bloc à extraire était une valeur composées de lettres et de chiffres.
      • Or pour STCK, c'est une valeur décimale qui contient donc un ".". Elle n'était donc pas prise en compte. Je les ai donc relâchées toutes les deux en disant n'importe quelle séquence non vide de caractères autres que des espaces (\S+)
      • Si toutes les valeurs de STCK sont  des valeurs décimales, ça peut être une bonne idée de convertir ces chaînes en float, en particulier si tu as besoin de coder un filtrage (par exemple, je ne veux que les entrées dont STCK est supérieur à un certain seuil). Si tu exportes directement entries en csv, ça n'est pas nécessaire car le fichier csv restera le même. Si tu décides d'apporter cette correction, corrige la valeur retournée par extract_data :
        return {
            "strt_m" : strt_m,
            "stck"   : float(stck),
        }

    Bonne chance

    0
  7. LALO_5656 Messages postés 31 Statut Membre 2
     

     
    Bonjour à tous,

    Désolé, voici l'exemple de fichier de sortie avec les renseignements du premier fichier ouvert (I16T04-001) 

    ID;STRT.M;WELL;STCK;FDL;BS.MM;DATE;OPE;UNIT
    I16T04-001;6.7;TAMR;GGWL_7800;ARTO;76.2;18/08/2022;SAMUEL;1500
    0
  8. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    Bonjour,

    As-tu testé et compris le code que je t'ai donné dans le message #5 ? Il te permet d'avoir les colonnes ID, STRT.M et STCK. As-tu des questions / remarques par rapport à ce code ?

    Si tu es toujours bloqué : ton message #6 : comment sont obtenus le contenu des colonnes WLL, DDL, BS.MM, DATE, OPE, UNIT ?

    Bonne chance

    0
  9. LALO_5656 Messages postés 31 Statut Membre 2
     

    Bonsoir effectivement ,je l'ai essayé mais mon fichier de sorti est vide.

    Dans mon message #6 je ecris ces valeurs pour que vous voyez les restes de données à extraires

    dans le premier fichier.

    MERCI

    0
    1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
       

      Bonjour,

      Chez moi le script marche donc je ne sais pas quoi te dire.

      (mando@silk) (~) $ rm -f output.csv 
      
      (mando@silk) (~) $ python3 toto.py
      (mando@silk) (~) $ python3 toto.py 
      extract_strt_m(STRT.M   6.70                                    :START DEPTH
      )
      extract_stck(STCK.    GGWL_7800                               :STACK
      )
      Processed I16T04-001
      ...
      ================================================================================
      filename,stck,strt_m
      I16T04-001,GGWL_7800,6.70
      
      (mando@silk) (~) $ cat output.csv 
      filename,stck,strt_m
      I16T04-001,GGWL_7800,6.70
      


      Et comme dtu ne dis pas comment remplir les colonnes te manquent, je ne vois pas trop comment t'aider.

      0