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 Delphi Discussion :

Parsing d'une ligne d'un CSV


Sujet :

Langage Delphi

  1. #1
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 091
    Points : 41 069
    Points
    41 069
    Billets dans le blog
    62
    Par défaut Parsing d'une ligne d'un CSV
    Bonjour,

    Même si j'ai trouvé une solution que je vais décrire après comment feriez-vous pour obtenir les noms des colonnes d'un fichiers CSV (généralement en première ligne)

    je suis "tombé" sur ce fichier CSV, à problème puisque les diverses colonnes ne sont pas entre guillemets
    CSV qui vient en fait d'un fichier Excel que l'utilisateur l'a customisé à sa façon
    Nom : Capture.PNG
Affichages : 465
Taille : 42,6 Ko
    Pour le traiter, après une sauvegarde en CSV, j'obtiens
    Modèle,Code couleur,Description Couleur,Size,Code EAN 14 (logistique),Gencode 13,"Conditionnement
    pour avoir dans une liste j'utilise ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ListeColonne.Lines.CommaText:=StringReplace(ContenuCSV.Lines[0],' ',#160,[rfReplaceAll]);
    qui fonctionne mais y a t-il mieux ?
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 745
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 745
    Points : 13 306
    Points
    13 306
    Par défaut
    Pourquoi pas simplement un TFDBatchMove si tu dois par la suite traiter ce fichier ?

    J'ai moi-même dans une app le besoin d'importer trois fichiers csv, tous formatés différemment !
    Un est avec point-virgule comme séparateur et sans guillemets dans les entêtes (nom de champs de plusieurs mots) mais guillemeté dans la donnée (qu'elle soit numérique, simple ou "multi" mots) ;
    un toujours avec point-virgule comme séparateur mais sans guillemets du tout ;
    et le dernier, le plus logiquement formaté, avec chaînes sur plusieurs mots guillemetées et la virgule comme séparateur.

    Et bien ce code suffit à charger mes trois types de fichier en mémoire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bmCSV.GuessFormat([taDelimSep, taFields]);
    bmCSV.Execute;

  3. #3
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 091
    Points : 41 069
    Points
    41 069
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    Merci pour la réponse.
    Oui j'ai effectivement à traiter les fichiers par la suite mais celui-ci est trop "particulier" pour un traitement Batchmove efficace.
    En particulier à cause des cases "fusion". Si tu regardes l'image, tu vois que le Modèle LOISIR VEL est appliqué sur plusieurs lignes, cependant dans le CSV cela ne s'applique pas
    LOISIR VEL,898,GRIS / BLEU,350,50900568983508,3664639005156,U = Unité
    ,898,GRIS / BLEU,360,50900568983607,3664639005163,U = Unité
    ,898,GRIS / BLEU,370,50900568983706,3664639005170,U = Unité
    ,898,GRIS / BLEU,380,50900568983805,3664639005187,U = Unité
    ,898,GRIS / BLEU,390,50900568983904,3664639005194,U = Unité
    ,898,GRIS / BLEU,400,50900568984000,3664639005200,U = Unité
    ,898,GRIS / BLEU,410,50900568984109,3664639005217,U = Unité
    ,898,GRIS / BLEU,420,50900568984208,3664639005224,U = Unité
    ,898,GRIS / BLEU,430,50900568984307,3664639005231,U = Unité
    ,898,GRIS / BLEU,440,50900568984406,3664639005248,U = Unité
    ,898,GRIS / BLEU,450,50900568984505,3664639005255,U = Unité
    ,898,GRIS / BLEU,460,50900568984604,3664639005262,U = Unité
    ,898,GRIS / BLEU,470,50900568984703,3664639005279,U = Unité
    J'ai aussi tenté l'approche ouverture du fichier XLS en utilisant SimpleExcel (trouvé sur GitHub) que j'ai même modifié pour FMX (puisque FMX le programme est )
    Traiter le fichier Excel en VCL (programme de la démo) plante, celui en FMX aussi mais là je n'ai pas fait assez d'essais pour dire si c'est mon portage ou le tableau, je m'y pencherais plus tard car cela m'a l'air pas mal du tout comme biblio.
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 534
    Points : 25 082
    Points
    25 082
    Par défaut
    StrictDelimiter permet d'éviter l'espace parasite si c'est ça le problème
    Il faut utiliser explicitement utiliser une TStringList puis faire un Assign à ton Lines

    le vrai problème dans un CSV c'est quand la donnée contient un CRLF, j'ai même vu un entête contenant un CRLF (mais avec les guillemets), il faut bien echapper les CRLF entre "
    Je crois que seul excel gère cela correctement
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 091
    Points : 41 069
    Points
    41 069
    Billets dans le blog
    62
    Par défaut
    Bonjour
    Citation Envoyé par ShaiLeTroll Voir le message
    StrictDelimiter permet d'éviter l'espace parasite si c'est ça le problème
    Il faut utiliser explicitement utiliser une TStringList puis faire un Assign à ton Lines
    J'y avais songé mais passer par un TStringList pour une seule ligne me paraissait
    autre petit problème mon résultat n'est pas tout à fait juste parce que l'utilisateur a trouvé malin de mettre 2 lignes pour la dernière colonne "Conditionnement
    seconde ligne UVC"

    Je crois que seul excel gère cela correctement
    j'en ai bien peur, je n'ai pas dit mon dernier mot pour voir si SimpleExcel me sortirait de ce pas, il faut déjà que je le migre correctement en FMX puis que je le teste avec des tableaux "simples"
    avant de m'embarquer sur cette inclusion dans l'application. Comme c'est une fonction qui ne servira que très peu, le jeu n'en vaut pas la chandelle si ce n'est pour ma curiosité
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  6. #6
    Membre expérimenté
    Avatar de retwas
    Homme Profil pro
    Développeur Java/Delphi
    Inscrit en
    Mars 2010
    Messages
    698
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Java/Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 698
    Points : 1 608
    Points
    1 608
    Billets dans le blog
    4
    Par défaut
    Ma réponse est peut être bête, mais pourquoi pas simplement un Split sur le caractère de délimitation (la virgule) ?

    EDIT : désolé je n'avais pas fait attention à la date du message

  7. #7
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    je suis justement en train de traiter des fichiers CSV

    j'ai utilisé mon propre code dont voici la déclaration

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    type
      TCSVField = record
        Name : string;
        Value: string;
        function AsInteger: Integer;
        function AsDate: TDate;
      end;
     
      TCSV = record
      private
        FFileName: string;
        FFile  : string;
        FIndex : Integer;
        FEOL   : Boolean;
        FEOF   : Boolean;
        function SkipChar(Ch: Char): Boolean;
        procedure DropChar(Ch: Char);
        function GetStr(var Str: string): Boolean;
      public
        Count : Integer;
        Line  : Integer;
        Fields: TArray<TCSVField>;
        function Load(const AFileName: string): Boolean;
        function FieldIndex(const AFieldName: string): Integer;
        function Next: Boolean;
      end;

    CSV.Load('...') copie le fichier en mémoire dans FFile
    GetStr() permet de prendre la prochaine chaîne en fixant EOL (fin de ligne) et EOF (fin de fichier)
    Load utilise cela pour créer le tableau FFields et renseigne la propriété Name

    la fonction Next() fait de même pour renseigner la propriété Value des TCSVField

    du coup je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    CSV.Load('fichier.Csv');
    date := CSV.FieldIndex('Date');
    ...
    while CSV.Next do
    begin
      MyDate := CSV.Fields[date].AsDate;
      ...
    end;


    et comme je suis bon, voici la foction GetStr
    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    function TCSV.GetStr(var Str: string): Boolean;
    var
      start: Integer;
      quote: Boolean;
    begin
      if FEol then
        Exit(False);
      start := FIndex;
      if SkipChar('"') then
      begin
        Inc(start);
        while not SkipChar('"') do
          Inc(FIndex);
        Str := Copy(FFile, start, FIndex - Start - 1);
        while SkipChar('"') do
        begin
          start := FIndex - 1;
          while not SkipChar('"') do
            Inc(FIndex);
          Str := Str + Copy(FFile, start, FIndex - Start - 1);
        end;
        if not SkipChar(';') then
        begin
          FEol := True;
          SkipChar(#13);
        end;
      end else begin
        while not SkipChar(';') do
          Inc(FIndex);
        Str := Copy(FFile, start, FIndex - Start - 1);
        FEol := SkipChar(#13);
      end;
      if FEol then
        SkipChar(#10);
      FEof := FIndex >= Length(FFile);
      Result := True;
    end;
    qui à la relecture contient un bug si le champ de la dernière colonne n'est pas entre guillemets

    mais il se trouve que tous les CSV que je traite utilisent des guillemets avec un séparateur point-virgule

    ce que j'aime dans l'écriture de ce genre de chose, c'est que c'est simple à faire et que je peux traiter tout les cas tordus assez simplement dans un code qui tient dans une unité de moins de 200 lignes aérées

    il est bcp plus difficile de faire un importateur CSV générique qui traite tous les cas tordus qu'on peut trouver dans ce format simple au départ.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 534
    Points : 25 082
    Points
    25 082
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    il est bcp plus difficile de faire un importateur CSV générique qui traite tous les cas tordus qu'on peut trouver dans ce format simple au départ.
    Je confirme, cela peut devenir compliquer de gérer, la présence d'entête (même de sous-entête), le présence d'un séparateur terminal (contraire à la RFC 4180), des lignes irrégulières ou même l'utilisation d'une colonne supplémentaire comme commentaire (sans qu'elle soit défini en entête), je n'ai jamais vu un seul CSV composé comme un autre, chaque source, chaque auteur faisant cela à sa sauce
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. Méthode de parsing pour une ligne de commande
    Par BiM dans le forum Langage
    Réponses: 12
    Dernier message: 27/07/2009, 16h40
  2. Transformer data (encolonne) en data csv sur une ligne
    Par chordially dans le forum VBA Access
    Réponses: 3
    Dernier message: 21/02/2009, 05h42
  3. Réponses: 55
    Dernier message: 16/11/2008, 17h32
  4. Réponses: 5
    Dernier message: 22/04/2008, 13h53
  5. [CSV] Taille d’une ligne d’un FICHIER
    Par sam01 dans le forum Langage
    Réponses: 1
    Dernier message: 22/01/2007, 11h22

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