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 :

[D2006][Excel] Conversion variant vers un double


Sujet :

Langage Delphi

  1. #1
    Membre averti

    Homme Profil pro
    ingénieur, retraité
    Inscrit en
    Février 2007
    Messages
    230
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : ingénieur, retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 230
    Points : 332
    Points
    332
    Par défaut [D2006][Excel] Conversion variant vers un double
    Bonjour,

    Pour mettre à jour un fichier de données Delphi j'utilise un fichier Excel obtenu par internet.
    Le programme Delphi, developé grâce à LFE (Pilotage OLE d'Excel ...), que je remercie, s'exécute correctement depuis plusieurs années.

    Actuellement quand cette procédure s'exécute, j'ai un probléme de lecture d'un Double :

    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
    procedure TFCotation.P_EnregistreCours(FichCours : TFileName);
    var
      vMSExcel, vLink, vXLWorkbks, vXlWorkbk, vWorkSheet, vCell : variant;
      FileName : string;
      BReadOnly : boolean;
      DateCours : String;
      CodeAct : string;      // action
      CoursAct : double;
     
    begin
    try
      try             
    ...
       vCell := vWorkSheet.Range[PosDate];
      DateCours := vCell.value;                                 // lecture d'une chaîne
      if MessageDlg('Date de mise à jour des cours : '+#13#10+ DateCours +#13#10+
        'Cette date est-elle valable ?', mtWarning,[mbYes,mbNo],0) =  mrNo then Exit;
     
      repeat                                                               
        vCell := vWorkSheet.Range[PosCode];
        CodeAct := vCell.value;                                  // lecture du Code,  chaîne
        vCell := vWorkSheet.Range[PosCours];
     
        CoursAct := vCell.value;                                //  erreur à la lecture du Double
     
        P_EnreCoursAct(CodeAct, DateCours, CoursAct); 
        . . .

    A la lecture de CoursAct j'ai une erreur de conversion avec le message : " impossible de convertir le variant de type (oleStr) en type (Double)". ?

    La valeur de la cellule étant de la forme : '28,81 €'.

    D'où peut provenir cette erreur ?

  2. #2
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 784
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 784
    Points : 5 915
    Points
    5 915
    Par défaut
    Bonjour,
    Citation Envoyé par paulfr Voir le message
    A la lecture de CoursAct j'ai une erreur de conversion avec le message : " impossible de convertir le variant de type (oleStr) en type (Double)". ?

    La valeur de la cellule étant de la forme : '28,81 €'.

    D'où peut provenir cette erreur ?
    AMHA, l'erreur provient de la présence du symbole monétaire dans la chaine de caractères.
    Essayez en affectant la valeur de la cellule dans une variable de type string, puis en y retirant le symbole monétaire, et enfin en convertissant cette variable avec StrToFloat().
    Philippe.

  3. #3
    Membre averti

    Homme Profil pro
    ingénieur, retraité
    Inscrit en
    Février 2007
    Messages
    230
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : ingénieur, retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 230
    Points : 332
    Points
    332
    Par défaut
    Bonjour,

    J'ai effectivement tenté de lire le contenu de la cellule :

    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
    repeat                                       // lecture du fichier excel
        vCell := vWorkSheet.Range[PosCode];
        CodeAct := vCell.value;
        vCell := vWorkSheet.Range[PosCours];
    //    CoursAct := vCell.value;                           // impossible de convertir le variant de type (oleStr) en type (Double)
         ChCours := VarToStr(vCell);          
        I := Pos('€', ChCours);
        if I > 0 then  ChCours[I] := ' ';    // suppression de €
        ChCours := Trim(ChCours);
                                                            // Lecture de ChCours
          K := 1;
         for J := 1 to Length(ChCours) - 1 do
         begin
           if ChCours[J] =  ',' then ChNC[J] := '.'
           else
             ChNC[K] := ChCours[J];                      // violation d'acces et erreur
     
             if (ChCours[J] >= '0') and ( ChCours[J] <= '9') then ChNC[K] := ChCours[J]
              else
                InputQuery('Chaine cours', 'Ce charactère n''est pas un chiffre '+ChCours[J], Ccar );
            Inc(K);
         end;
     ...
    A l'affectation du premier caractère de ChCours à ChNC (string) j'ai une violation d'accès.

    Comment sortir de ce piége ?

    Sur Internet on propose d'utiliser un programme : " ParetoLogic PC Health Advisor_FR.exe " pour éliminer les violations.
    L'un d'entre vous l'a t'il utilisé ?
    Est'il efficace et fiable ?

    Merci à PhB pour sa réponse, j'avais d'abord supprimé le €, mais ensuite j'obtenais la valeur bizarre "28.81, d'où erreur. et j'ai cherché
    une autre solution (ci-dessus), avec le même résultat.

  4. #4
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 041
    Points : 40 950
    Points
    40 950
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    une petite fonction rapide (écrite en D7 donc utilisable avec D2006)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
        uses ...,sysUtils;
        .....
        function CurrencyStringtoDouble(Cs : string) : Double;
        var r : string;
        begin
          r:=StringReplace(Cs,CurrencyString,'',[rfReplaceAll]);     // enlève l'€
          r:=StringReplace(r,ThousandSeparator,'',[rfReplaceAll]); // enlève le séparateur de millier pas forcément nécessaire 
          r:=Trim(r);                                                                // enlève les espaces 
          result:=StrToFloatDef(r,0.00);                                     // erreur de conversion donne 0 
        end;
     
        // utilisation à tester 
        CoursAct:=CurrencyStringToDouble(vCell.value);
    améliorations possibles de la fonction : obtenir le format de la cellule ou d'excel en ce qui concerne les devises, séparateurs décimaux et milliers
    car dans cette fonction c'est les settings du poste qui sont pris en compte
    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

  5. #5
    Membre averti

    Homme Profil pro
    ingénieur, retraité
    Inscrit en
    Février 2007
    Messages
    230
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : ingénieur, retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 230
    Points : 332
    Points
    332
    Par défaut
    Bonjour,

    Merci à Sergio pour sa fonction.
    Je vais tester .

    PL

  6. #6
    Membre averti

    Homme Profil pro
    ingénieur, retraité
    Inscrit en
    Février 2007
    Messages
    230
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : ingénieur, retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 230
    Points : 332
    Points
    332
    Par défaut
    Bonjour.

    J'ai essayé la solution de SergioMaster qui facilite le remplacement des caractères.
    Mais à la conversion chaîne vers nombre j'ai toujours l'erreur de conversion ({1})

    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
     vCell := vWorkSheet.Range[PosCode];
        CodeAct := vCell.value;
        vCell := vWorkSheet.Range[PosCours];
     
      // solution SergioMaster
        ChCours := StringReplace(vCell.value, ',', '.', [rfReplaceAll]); // '29.67 €'
        ChCours := StringReplace(ChCours, '€', ' ', [rfReplaceAll]);     // '29.67  '
        ChCours := Trim(ChCours);                                                      // '29.67'
     
        I := Length(ChCours);                     // 6
        Caract := Chcours[1];                     // '2'
        Caract := Chcours[3];                     // '.'
        Caract := Chcours[5];                     // '7'
     
         ChNC := '';
     
    {3}  For J:=1 to Length(Chcours)-1  do
         begin
           Caract := ChCours[J];
           ChNC := ChNC + Caract;
         end;
         CoursAct := StrToFloat(ChNC);          // ->  29.67    OK
    {---------------------------------------------------------------------------------------
    {2}     for J := 1 to Length(Chcours)-1  do   ChNC[J] := ChCours[J];
            // Exception EAccessViolation                 VIOLATION d'ACCES
     
    {1}    CoursAct := StrToFloat(ChCours);  // Exception   EConvertError
                  //  "29.67' n'est pas une valeur en virgule flottante correcte
    ----------------------------------------------------------------------------------}
    Ensuite ({2}) j'ai tenté de faire une affectation caractère par caractère. Au premier caractère elle déclenche une "Violation d'accès".

    {3} J'ai constaté que la longueur de la chaîne était correcte et que l'affectation à un Char (Caract) semblait possible.. En passant par l'intermédiaire d'un caractère la nouvelle chaîne obtenue (ChNC) convertie en Double s'effectue sans erreur.

  7. #7
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 784
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 784
    Points : 5 915
    Points
    5 915
    Par défaut
    Bonjour,

    Quelques remarques :
    1. Solutions {2} et {3} : votre conversion n'est pas complète :
      La boucle sur la chaine de caractères doit itérer de 1 à Length(Chcours).
    2. Solutions {2} et violation d'accès :
      C'est normal !
      Votre code ne le montre pas, mais vos explications confirme ce qui suit :
      Votre chaine de caractère est initialisée à vide.
      Puis vous essayez d'affecter dans la boucle une zone mémoire non allouée
    3. Concernant l'erreur de conversion, je ne vois que le séparateur décimal qui ne correspond pas à vos paramètres régionaux... vérifiez votre code...
    Philippe.

  8. #8
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 041
    Points : 40 950
    Points
    40 950
    Billets dans le blog
    62
    Par défaut
    Bonjour,
    // solution SergioMaster
    ChCours := StringReplace(vCell.value, ',', '.', [rfReplaceAll]); // '29.67 €'
    ChCours := StringReplace(ChCours, '€', ' ', [rfReplaceAll]); // '29.67 '
    ChCours := Trim(ChCours); // '29.67'
    pas totalement la solution proposée car j'utilisais ThousandSeparator (et non DecimalSeparator) et CurrencyString pour faire les test de remplacement.
    @paulfr ton erreur me semble être que tu veux absolument mettre un point décimal où dans ce cas il n'y avait pas besoin puisque strtofloat utilise le DecimalSeparator du poste pour faire la conversion :
    sur un poste avec DecimalSeparator=',' alors Strtofloat('29,67') -> 29.67 StrToFloat('29.67') -> Erreur

    De même j'avais indiqué qu'il faudrait certainement
    obtenir le format de la cellule ou d'excel en ce qui concerne les devises, séparateurs décimaux et milliers
    car dans cette fonction c'est les settings du poste qui sont pris en compte
    car rien n'indique que le tableau excel soit dans la même "langue" que le poste. Si je sais le faire avec OpenOffice je ne sais pas et surtout ai aucun moyen (pas de excel sous la main) de tester cette partie
    peut être quelque chose comme strDecimal := ExcelApplication.International[xlDecimalSeparator,LCID]; où lcid est un integer obtenu par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lcid:=GetUserDefaultLCID;
    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

  9. #9
    Membre averti

    Homme Profil pro
    ingénieur, retraité
    Inscrit en
    Février 2007
    Messages
    230
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : ingénieur, retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 230
    Points : 332
    Points
    332
    Par défaut
    Bonjour,

    Primo - je rappelle que j'ai utilisé pendant des années le code logique "CoursAct := vCell.value; " et qu'une Exception, récente,
    "ce n'est pas un double", m'a obligé à trouver une autre solution.

    J'ai toujours utilisé le point décimal.

    @ SergioMaster
    J'ai surtout retenu "StringReplace" que je ne connaissais pas.

    @PH.B
    J'ai indiqué les lignes 23 à 29 pour montrer les solutions essayées qui se terminaient par une Exception (elles sont entre accolades).

    Solution (3) ligne 17
    Dans Delphi For n'utilise pas l'incrémentation, c'est automatiquement l'unité

    Instructions for
    Une instruction for, à la différence des instructions repeat et while, nécessite la
    spécification explicite du nombre d'itérations que la boucle doit effectuer.
    L'instruction for a la syntaxe suivante : for compteur := valeurInitiale to
    valeurFinale do instruction ou for compteur := valeurInitiale downto valeurFinale do instruction where
    * compteur est une variable locale (déclarée dans le bloc contenant l'instruction for) de type scalaire sans aucun qualificateur.
    * valeurInitiale et valeurFinale sont des expressions compatibles pour l'affectation avec compteur.
    * instruction est une instruction simple ou structurée qui ne modifie pas la valeur de compteur.
    L'instruction for affecte la valeur valeurInitiale à compteur, puis exécute répétitivement instruction, en incrémentant ou en décrémentant compteur après chaque itération. La syntaxe for...to incrémente compteur alors que la syntaxe for...downto le décrémente.
    ...
    En définitive pour me dépanner j'ai du passer par l'intermédiaire d'un Char.

    Merci à tous.

    PL

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

Discussions similaires

  1. [excel] Conversion kml vers excel
    Par SandyF dans le forum XQUERY/SGBD
    Réponses: 2
    Dernier message: 25/11/2010, 16h59
  2. Conversion txt vers excel
    Par tardieub dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 23/10/2007, 09h18
  3. Conversion hexa vers double
    Par EnigmuS dans le forum C
    Réponses: 13
    Dernier message: 16/05/2007, 14h06
  4. Problème conversion float vers double
    Par jhenaff dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 27/01/2006, 10h39
  5. conversion : VARIANT FAR* URL vers CString
    Par kam dans le forum MFC
    Réponses: 2
    Dernier message: 29/03/2004, 13h32

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