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 :

Fonction Chaine[i] vide


Sujet :

Langage Delphi

  1. #1
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut Fonction Chaine[i] vide
    Bonsoir à toutes et à tous,

    J'ai fais rapidos une p'tite function pour récupérer les valeurs des colonnes d'un fichier CSV :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Function TFPrincipal.RetourneChaine(Chaine:String;Colonne: Integer):String;
    Var
      i: integer;
      CompteSeparateur: Integer;
    begin
      Result := '';
      CompteSeparateur := 0;
      for i := 0 to Length(Chaine) do
      begin
        if Chaine[i] = ';' then Inc(CompteSeparateur);
        if CompteSeparateur = Colonne then exit;
        if (CompteSeparateur = Colonne - 1) And (Chaine[i] <> ';') then Result := Result + Chaine[i];
      end;
    end;
    Utilisation :

    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
    //...
                      Open;
                      for i := LigneDebutLecture to FichierCSV.Count - 1 do
                      begin
                        Insert;
                        FieldByName('CodeDossier').AsString := RetourneChaine(FichierCSV.Strings[i],1);
                        FieldByName('EAN').AsString         := RetourneChaine(FichierCSV.Strings[i],2);
                        FieldByName('CodeArticle').AsString := RetourneChaine(FichierCSV.Strings[i],3);
                        FieldByName('Libelle').AsString     := RetourneChaine(FichierCSV.Strings[i],4);
                        FieldByName('FamilleA').AsString   := RetourneChaine(FichierCSV.Strings[i],5);
                        FieldByName('FamilleP').AsString  := RetourneChaine(FichierCSV.Strings[i],6);
                        FieldByName('Actif').AsBoolean      := StrToBool(RetourneChaine(FichierCSV.Strings[i],7));
                        if GererMontant then
                        begin
                          FieldByName('PrixUnitNetAchat').AsCurrency := StrToFloat(RetourneChaine(FichierCSV.Strings[i],8));
                          FieldByName('PrixUnitNetVente').AsCurrency := StrToFloat(RetourneChaine(FichierCSV.Strings[i],9));
                        end;
                        Post;
                      end;
    //...
    Mon problème est que toutes les colonnes sont reprise sauf la première !!!, la fonction me retourne du vide.

    j'ai essayé avec un Char ou passer par un String pour concaténation, sa change rien. Si je place un showmessage(Chaine[i]) en dessous des trois if, il m'affiche bien les lettres une par une.

    What is this thing ?

  2. #2
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Hé buzz, hééééé ohééééé

    Commence ta boucle à 1 dans ta fonction sa fonctionnera mieux... abruti de buzz.

    Oupss Désolé.

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    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 586
    Points : 25 262
    Points
    25 262
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Result := Result + Chaine[i];
    J'espère que tu n'es pas en D4 à D7, une telle concatenation char par char est une opération fort lente !

    J'ai fait une GetString, je n'ai encore jamais eu l'occasion de l'utiliser
    je t'ai mis le code le plus récent à la fin de ma réponse, cela gère une chaine qui ne termine pas par un ; et que l'on souhaite tout de même extraire la dernière colonne

    Le découpage CSV est un grand classique sur le forum, comme tu exploites plusieurs colonnes autant découper le tout en une seule passe !

    Par la TStringList et DelimitedText avec StrictDelimiter qui n'existe pas en D3, et l'espace, CR\LF sont des séparateurs par défaut ce qui parasite le découpage csv
    SplitString de StrUtils

    Construire un tableau à partir d'une chaine (Spliter) évoque mon Explode et ExtractStrings
    Votre Avis : Optimisation des performances pour le chargement de fichier CSV
    Mettre une chaine dans un tableau
    Très gros fichier CSV


    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
    function GetString(const DelimitedText: string; Delimiter: Char; Index: Integer = 1): string;
    var
      idtb, idte, occ: Integer;
    begin
      if Index <= 0 then
        Index := 1;
     
      idtb := 0;
      idte := 1;
      occ := 0;
      while (idte <= Length(DelimitedText)) and (occ < Index) do
      begin
        if DelimitedText[idte] = Delimiter then
        begin
          Inc(occ);
          if occ < Index then
            idtb := idte;
        end;
        Inc(idte);
      end;
      if (occ > 0) and (idte >= Length(DelimitedText)) then
        Inc(Occ);
     
      if occ = 0 then
        Result := DelimitedText
      else
        if occ =  Index then
          if idte <= Length(DelimitedText) then
            Result := Copy(DelimitedText, idtb+1, idte-idtb-2)
          else
            Result := Copy(DelimitedText, idtb+1, idte-idtb-1)
        else
          Result := '';
    end;

  4. #4
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    J'espère que tu n'es pas en D4 à D7, une telle concatenation char par char est une opération fort lente !
    No souci je suis sous D2009.


    Citation Envoyé par ShaiLeTroll Voir le message
    J'ai fait une GetString, je n'ai encore jamais eu l'occasion de l'utiliser
    En fait toi tu place tes idte et itdb avant et ensuite un coup de copy, avec possibilité de changer de delimiteur. Moi le délimiteur sera forcément le ';' et le format changera jamais (fichier de nos amis suisse ). Par contre une concaténation de caractère par caractères, je voyais pas l'inconvénient.

    Citation Envoyé par ShaiLeTroll Voir le message
    Le découpage CSV est un grand classique sur le forum, comme tu exploites plusieurs colonnes autant découper le tout en une seule passe !
    Par la TStringList et DelimitedText
    Surtout pas dans mon cas, je te raconte pas le traitement après lol, mes lignes sont différentes, mes colonnes non, alors un délimiteur imagine le mélange. J'utilise ce système juste avant.

    Mon problème est que le premier caractère de la chaîne était un caractères < ASCII 20, je sais pas lequel en fait, et placer la boucle à 1 à résolu le prob.

    Merci Shail, pour toutes tes informations.

  5. #5
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    Salut buzz ça vas mon grand ça faisait longtemps !


    CSV ?! aller hop ça c'est cadeaux :
    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
     
    var CSV : TStringList;
      X : integer;
    begin
      CSV := TStringList.Create;
      try
        CSV.Delimiter := ';';
        CSV.StrictDelimiter := true;
     
        CSV.DelimitedText := 'une;chaine;csv;qui;"fonctionne même";"avec les champs protégé"';
     
        if CSV.Count = 6 then // si il y a bien 6 colonnes
        begin
          for X := 0 to 5 do
            showMessage(CSV[X]);
        end;
      finally
        CSV.Free;
      end;
    end;

    en cadeaux mon unité CSVList en PJ, à mettre dans le repertoire Lib de delphi, tu peux lancer le dproj si tu veux installer le TCSVStringList (compo non visuel qui gere un fichier CSV en tant que tel).
    Fichiers attachés Fichiers attachés

  6. #6
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Tiens le docteur est parmi nous, merci pour ta lib , je regarderai ça.

    Par contre pour ton cadeau, mon fichier CSV n'a pas qu'une seul ligne.
    Mais on peut l'utiliser justement pour une ligne du CSV de départ, comme la function que j'ai mis plus bas, a savoir si c'est plus rapide que celle de SHAIL, en tout cas c'est vachement plus simple.

    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
    Function ReturnColonneCSV(LigneCSV: String; Index: Integer) : String;
    var 
    CSV : TStringList;
    begin
      CSV := TStringList.Create;
      try
        CSV.Delimiter := ';';
        CSV.StrictDelimiter := true;
     
        CSV.DelimitedText := LigneCSV;
     
        Result := CSV[Index];
     
      finally
        CSV.Free;
      end;
    end;
    Bye

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    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 586
    Points : 25 262
    Points
    25 262
    Par défaut
    Citation Envoyé par BuzzLeclaire Voir le message
    mon fichier CSV n'a pas qu'une seul ligne.
    Tu peux utiliser deux TStringList, une pour lire le fichier (c'est on actuel FichierCSV) une autre pour découper chaque ligne, après tout dépend si ton fichier peut être vraiment lu ligne ou par ligne

    Citation Envoyé par BuzzLeclaire Voir le message
    a savoir si c'est plus rapide que celle de SHAIL
    Pour vouloir rester dans la nieme colonne, ton code va splitter autant de fois que de colonne exploitée, autant le faire une seule fois puis voir ce qu'il est possible d'y lire !

    regarde ce que cela donne

    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
    var
      LineCSV: System.Types.TStringDynArray;
     
      function GetColonneCSV(Index: Integer): string;
      begin
        if Index <= Length(LineCSV) then
          Result := LineCSV[Index - 1] // 1 à n -> 0 à n-1
        else
          Result := '';
      end;
     
    begin
      ...
                      Open;
                      for i := LigneDebutLecture to FichierCSV.Count - 1 do
                      begin
                        Insert();
     
                        LineCSV = SplitString(FichierCSV.Strings[i], ';'); 
                        // un seul accès à Strings[i] = économie de temps !
                        // un seul découpage = économie de temps ! 
     
                        FieldByName('CodeDossier').AsString := GetColonneCSV(1);
                        FieldByName('EAN').AsString         := GetColonneCSV(2);
                        FieldByName('CodeArticle').AsString := GetColonneCSV(3);
                        FieldByName('Libelle').AsString     := GetColonneCSV(4);
                        FieldByName('FamilleA').AsString    := GetColonneCSV(5);
                        FieldByName('FamilleP').AsString    := GetColonneCSV(5);
                        FieldByName('Actif').AsBoolean      := StrToBoolDef(GetColonneCSV(7), false);
                        if GererMontant then
                        begin
                          FieldByName('PrixUnitNetAchat').AsCurrency := StrToFloatDef(GetColonneCSV(8), 0);
                          FieldByName('PrixUnitNetVente').AsCurrency := StrToFloatDef(GetColonneCSV(9), 0);
                        end;
                        Post();
                      end;
    //...
    si tu veux comparer c'est avec Explode qui gère les " et autres subtilités bien plus lente que ExplodeLazy

    D7, Explode sera plus rapide que DelimitedText, voir TStringList et fréquence des mots.
    en D2007+ ou avec FastMM, c'est l'inverse

    L'utilisation de DelimitedText comme je l'évoquais dans ma réponse précédente est un classique, c'est même une des premières solutions, avant l'apparition de StrictDelimiter (2006 ?) cette propriété avait de nombreux défauts comme l'utilisation de l'espace, la tabulation ... comme séparateur permanent

    Sinon à savoir que SplitStrings de StrUtils utilisent un algo similaire à mon ExplodeLazy avec une prédiction de l'allocation qui avec FastMM n'est pas aussi intéressant qu'en D7

    Autant utiliser le code RTL fourni par embarcadero si il existe surtout si c'est précisément LA fonction pour CE problème

  8. #8
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Super ta dernière idée ShaiL,

    Je sais pas où tu as été cherché System.Types.TStringDynArray; mais franchement faut connaitre..

    GG

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

Discussions similaires

  1. Fonction chaine ?
    Par sachav dans le forum C
    Réponses: 11
    Dernier message: 29/12/2007, 20h57
  2. Problème de fonction avec cellule vide
    Par Samjeux dans le forum Excel
    Réponses: 4
    Dernier message: 14/06/2007, 08h45
  3. Réponses: 1
    Dernier message: 30/03/2007, 16h38
  4. Problème fonctions chaines de caractères.
    Par Hayron06 dans le forum C
    Réponses: 12
    Dernier message: 13/11/2006, 21h47
  5. [langage] Comment tester si une chaine est vide
    Par |Bio dans le forum Langage
    Réponses: 4
    Dernier message: 04/05/2005, 15h05

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