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

Macros et VBA Excel Discussion :

vba : supprimer des colonnes dans un fichier csv


Sujet :

Macros et VBA Excel

  1. #1
    Membre à l'essai
    vba : supprimer des colonnes dans un fichier csv
    Bonjour,

    J'ai des fichiers csv contenant des données alphabétique et numérique, l'ensemble séparé par des virgules.
    Je voudrais pouvoir modifier les fichiers csv via vba pour supprimer des "colonnes", ou dit autrement des valeurs entre 2 virgules en ayant connaissance du numéro des virgules (par exemple si je veux supprimer la 2ème "colonne", c'est entre la 1ère et 2ème virgule), tout en gardant le format .csv

    Est-ce que vous pouvez m'orientez sur la méthode à utiliser pour faire ceci ?

  2. #2
    Membre à l'essai
    Bonjour,
    Si tu importes ton documents dans excel en précisant le caractère séparateur, il devrait organiser ton fichier csv dans une feuille excel.
    Tu pourras ensuite modifier les colonnes comme pour une feuille classique en choisissant le numéro de colonne/ligne, y compris via VBA non?
    Ensuite tu réexportes en .csv

  3. #3
    Membre à l'essai
    L'objectif est de le faire via une macro parce que je vais avoir un grand nombre de fichier à traiter.
    Donc, je voudrais pouvoir le faire sans avoir à importer puis exporter, ce qui risque d'être assez long.

  4. #4
    Responsable
    Office & Excel

    Salut.

    Tu pourrais essayer ceci, qui travaille avec des arrays et une feuille Excel (la feuille active du classeur, à adapter). Pour le temps de traitement, tout dépend de la taille de ton fichier: 20000 lignes de 5 colonnes ramenées à 3 en 2 secondes.

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    Sub Treatment1(ColumnsToDelete, SourceName As String, Optional TargetName As String)
      Dim s As ADODB.Stream
      Dim Source As String
      Dim t, r
      Dim i As Long, j As Long, cols As Long
      Dim Text As String, Target As String
     
      If TargetName = "" Then TargetName = SourceName
     
      Set s = New ADODB.Stream
      s.Charset = "utf-8"
      s.Open
      s.LoadFromFile SourceName
      Source = s.ReadText
      s.Close
     
      t = Split(Source, vbCrLf)
      For i = 0 To UBound(t)
        r = Split(t(i), ",")
        If UBound(r) <> -1 Then
          If cols = 0 Then cols = UBound(r)
          Range("a" & i + 1).Resize(1, UBound(r) + 1).Value = r
        End If
      Next i
     
      For i = UBound(ColumnsToDelete) To 0 Step -1
        Cells(1, ColumnsToDelete(i)).EntireColumn.Delete
      Next i
     
      t = Cells(1, 1).Resize(UBound(t) + 1, cols - UBound(ColumnsToDelete)).Value
      For i = 1 To UBound(t)
        Text = ""
        For j = 1 To UBound(t, 2)
          Text = Text & t(i, j) & ","
        Next j
        Text = Left(Text, Len(Text) - 1)
        Target = Target & Text & vbCrLf
      Next i
     
      Set s = New ADODB.Stream
      s.Charset = "utf-8"
      s.Open
      s.WriteText Target
      s.SaveToFile TargetName, adSaveCreateOverWrite
    End Sub
     
    Sub Test1()
      Dim Debut As Date, Fin As Date
     
      Debut = Now
      Treatment1 VBA.Array(2, 4), "c:\data\temp\source.csv", "c:\data\temp\target.csv"
      Fin = Now
      Debug.Print Format(Fin - Debut, "hh:mm:ss")
    End Sub
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  5. #5
    Expert confirmé
    Bonjour,
    Citation Envoyé par Pierre Fauconnier Voir le message
    .
    L'éternel problème des fichiers csv c'est qu'il ne sont pas standardisés, notamment au niveau du séparateur de lignes, beaucoup n'utilises que vbLf, d'autre vbCrLf, et certains uniquement vbCr.
    Le Split(Source, vbCrLf) risque de ne pas produire l'effet recherché : séparer les différents enregistrements (ou lignes).
    D'autre part, il arrive fréquemment qu'un champ texte (délimité par ") contienne un séparateur de ligne, par exemple dans les adresses. Dans ce cas le split coupe en deux (ou plus) un enregistrement.
    Cordialement,
    Patrice
    Personne ne peut détenir tout le savoir, c'est pour ça qu'on le partage.

    Pour dire merci, cliquer sur et quand la discussion est finie, penser à cliquer sur

  6. #6
    Responsable
    Office & Excel

    Salut Patrice,

    C'est toujours à tester, avec un CSV. Il faudrait s'en tenir à la norme, mais il n'y a pas vraiment de norme CSV comme pour un xml, par exemple.

    Normalement, lorsque du texte est censé contenir un caractère de contrôle, il doit être encadré de guillemets. Perso, j'ai écrit un parseur de csv parce que plusieurs de mes clients utilisent des CRM/ERP qui permettent une extraction "Excel" (ha ha ha) sous forme de CSV. S'ils respectent la règle de mettre le texte entre guillemets lorsqu'elle contient des caractères de contrôle et que l'on double les guillemets à l'intérieur d'une zone de texte, ce qui est préconisé par la "norme", le parseur fonctionne bien.

    Donc, oui, d'une façon générique, la méthode avec SPLIT a ses limites. A voir par le demandeur pour son besoin précis. Perso, je ne suis pas forcément fan d'une extraction "à la Excel" car la page de code utilisée est souvent "Windows-8859" ou "ISO 8859-1" à la place de "utf-8"... Ca n'aide pas. XML et json ont normé en utf-8 et c'est quand même plus simple à gérer.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  7. #7
    Membre éclairé
    Bonjour,
    Par défaut le caractère de séparation de colonne d'un CSV n'est pas les points virgule mais la virgule.

    Je t'invite à récupérer tes données via un Rerordset et une connexion AdoDb!

    Tu pourras même à ta guise sélectionner les colonnes que tu veux garder.

  8. #8
    Responsable
    Office & Excel

    Pour compléter Thumb , je livre ici le résultat de mes tests. Le manque de norme CSV oblige à spécifier les formats spécifiques de tes CSV.

    je passe par un fichier Shema.ini déposé dans le dossier qui contient la source et dans lequel sera déposé le résultat. Ce fichier schema.ini contient les informations de format des fichiers traités. Il contiendra un bloc par fichier, que ce fichier soit source ou cible. En première ligne de bloc, on a le nom du fichier, puis les spécifications du CSV.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [source.csv]
    Format=Delimited(<img src="images/smilies/icon_wink.gif" border="0" alt="" title=";)" class="inlineimg" />
    DecimalSymbol=.
    ColNameHeader=TRUE
     
    [Target.csv]
    Format=Delimited(<img src="images/smilies/icon_wink.gif" border="0" alt="" title=";)" class="inlineimg" />
    DecimalSymbol=.
    ColNameHeader=TRUE
    TextDelimiter=


    En partant d'un fichier source.csv contenant 5 colonnes (Prénom, Nom, Montant, Service, Actif), je crée le fichier target.csv contenant Prénom, Montant, Service avec le code suivant:
    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
    Sub Test1()
      Dim cn As Object
      Dim Path As String, Source As String, Target As String
     
      Path = "c:\data\Temp\"
      Source = "source.csv"
      Target = "target.csv"
      If Dir(Path & Target) <> "" Then Kill Path & Target
     
      Set cn = CreateObject("ADODB.Connection")
      cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & Path & ";Extended Properties='text;HDR=NO;CharacterSet=65001';"
      cn.Open
      cn.Execute "select Prénom, Montant, Service into " & Target & " from " & Source
      cn.Close
      Set cn = Nothing
    End Sub
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  9. #9
    Membre éclairé
    Bonjour Pierre
    Attention dans les requêtes [Target#Csv]

  10. #10
    Responsable
    Office & Excel

    Salut Thumb

    Ton message est tellement sibyllin que je ne l'ai pas compris...

    Ma solution a été testé et fonctionne. Si tu en as une autre ou que tu rencontres un problème, explique-toi, mais perso, les devinettes, j'ai passé l'âge
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  11. #11
    Membre éclairé
    Non c'est très bien mon bémol c'est les points dans les requêtes SQL ado est allergique , chez moi ça passe pas,il faut les replace par #, pas d'autres remarques.

    Source = "source#csv"
    Target = "target#csv"

  12. #12
    Responsable
    Office & Excel

    J'ai eu cela une fois, parce que j'avais laissé le datasource en database, et du coup, il ne trouvait la requête xxx#csv alors que j'avais passé xxx.csv. Mais en attaquant du csv, je n'ai pas rencontré ce problème. Peut-être parles-tu de ado.net alors qu'ici on parle de adodb?
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  13. #13
    Membre éclairé
    Le plus important c'est que notre ami trouve une solution efficace et ton Select into est bien mieux que ma proposition de recordset !

    Je remplace systèmatiquemt les points par des #

  14. #14
    Responsable
    Office & Excel

    Avec les points, je n'ai pas de problèmes. Avec le #, si la table existe déjà, il ne veut pas la remplacer et se met en erreur.

    Avec ta remarque, doit-on conclure que l'utilisation du . ou du # dépend de l'environnement? J'ai quand même un doute là-dessus car cela voudrait dire que la solution n'est pas forcément portable telle quelle...

    d'où ma question: Parles-tu d'ADO.Net ou de ADODB?
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  15. #15
    Membre éclairé
    Bonjour Pierre,
    Je parle bien d'ADODB.

    EN VB.NET je ne me suis jamais posé la question, je mets #

  16. #16
    Responsable
    Office & Excel

    Merci pour la précision
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  17. #17
    Membre éclairé
    Énumère dans debug le nom des tables avec OpenSchema.

  18. #18
    Responsable
    Office & Excel

    Ok. Vu. Je vais voir à adapter ma façon de faire

    Merci
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    Vous avez apprécié la réponse? =>
    ---------------

  19. #19
    Membre éclairé
    Code TableExiste :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
    Sub test()
    Path = "C:\Test"
    Dim Source As String, Target As String
    Source = "source#csv"
    Target = "target#csv"
    Dim Cn As Object
     Set Cn = CreateObject("ADODB.Connection")
      Cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & Path & ";Extended Properties='text;HDR=NO;CharacterSet=65001';"
      
      If TableExiste(Cn, Target) Then MsgBox "Drop Table!"
       Cn.Execute "select Prénom, Montant, Service into " & Target & " from " & Source
      Cn.Close
      
    End Sub
    Function TableExiste(Cn As Object, TableName As String) As Boolean
    With Cn.OpenSchema(20)
        If Not .EOF Then
          .Filter = "TABLE_NAME ='" & TableName & "'"
           TableExiste = Not .EOF
        End If
        .Close
    End With
    End Function

    Notes que la requête drop table supprime effectivement le CSV mais efface également toute trace dans shema.ini de même que le into de ta requête de sélection ré implementera le .ini!

###raw>template_hook.ano_emploi###