Conversione di file CSV con VB 2008

Spesso mi è capitato, e ancora oggi mi capita, di avere a che fare con file CSV (file di testo con “Campi Separati da Virgola”) che, aperti con Excel, vengono caricati senza separare i vari campi. In pratica, ogni riga (record) viene inserito nella corrisponte cella della prima colonna.

Il motivo è semplice: questi file CSV sono stati creati con sistemi le cui impostazioni internazionali sono impostate secondo il sistema americano, con la virgola per la separazione del campo e il punto per separare i valori interi dai decimali. Nelle impostazioni italiane, invece, ovviamente è diverso: la virgola è il separatore dei decimali, mentre il punto e virgola è il separatore dei campi.

Come risolvere questo problema per poter caricare i dati in un foglio Excel?

Una prima soluzione che ho tentato è quella di sostituire tutti i separatori direttamente in Excel, salvando poi nuovamente in file CSV. Il risultato è deludente, in quanto Excel registra, sì, le modifiche, ma circonda ciascuna riga da doppi apici, rendendo ugualmente impossibile la lettura campo per campo.

Una seconda soluzione è quella di aprire NotePad e fare la sostituzione manuale, prima da virgola a punto e virgola e poi da punto a virgola. Questa soluzione risolve il problema ma è macchinosa, un po’ difficile da ricordare e poi straordinariamente LENTA.

Da qui mi è venuto in mente che tutto questo lavoro può essere fatto in modo più efficace con un programmino di utilità, naturalmente in VB 2008 (anche la versione 2.0 del Framework .NET va bene, quindi si può fare anche in VB 2005).

Ho creato un nuovo progetto di tipo Applicazione Windows Form e ho inserito due controlli Label (il nome non ha importanza) e quattro caselle di testo: txtCartella e txtFile per caricare rispettivamente il nome della cartella (per aprire sempre la stessa cartella se i file da convertire sono più di uno) e il nome del file, nonché txtTestoDaConvertire e txtTestoConvertito, più grandi e multilinea, con ovvio significato.

Poi ho creato un menu per gestire le varie azioni da eseguire. Il menu ha la seguente struttura:

  • File
    … Apri
    …… Cartella
    …… File
    … Salva
    … Chiudi file
    … Esci
  • Conversione
    … CSV inglese –> CSV italiano
    … CSV italiano –> CSV inglese

Infine ho inserito i seguenti controlli, per gestire tutte le operazioni su file e nel menu: MenuStrip, StatusStrip, ToolStrip, FolderBrowserDialog, OpenFileDialog e SaveFileDialog.

Il form ha quindi il seguente aspetto finale:

CSVconverterForm

Infine, il codice che ho inserito è il seguente:

Public Class Form1
   Private Sub CartellaToolStripMenuItem_Click(ByVal sender _
           As System.Object, ByVal e As System.EventArgs) _
           Handles CartellaToolStripMenuItem.Click
      Dim nomeCartella As String = ""
      If FolderBrowserDialog1.ShowDialog = _
             Windows.Forms.DialogResult.OK Then
         nomeCartella = FolderBrowserDialog1.SelectedPath
      End If
      Me.txtCartella.Text = nomeCartella
   End Sub

   Private Sub FileToolStripMenuItem1_Click(ByVal sender _
           As System.Object, ByVal e As System.EventArgs) _
           Handles FileToolStripMenuItem1.Click
      Dim nomeFile As String = ""
      OpenFileDialog1.InitialDirectory = Me.txtCartella.Text
      If OpenFileDialog1.ShowDialog = _
             Windows.Forms.DialogResult.OK Then
         nomeFile = OpenFileDialog1.FileName
      End If
      Me.txtFile.Text = nomeFile
      Me.txtTestoDaConvertire.Text = _
           My.Computer.FileSystem.ReadAllText(Me.txtFile.Text)
   End Sub

   Private Sub ToolStripMenuItem2_Click(ByVal sender _
           As System.Object, ByVal e As System.EventArgs) _
                Handles ToolStripMenuItem2.Click
      Dim nomeFile As String = Me.txtFile.Text
      Dim nomeCompleto As String = ""
      SaveFileDialog1.FileName = nomeFile
      If SaveFileDialog1.ShowDialog = _
              Windows.Forms.DialogResult.OK Then
         nomeCompleto = SaveFileDialog1.FileName
         My.Computer.FileSystem.WriteAllText( _
              nomeCompleto, Me.txtTestoConvertito.Text, False)
      Else
         MessageBox.Show("Operazione annullata")
      End If
   End Sub

   Private Sub Label2_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles Label2.Click
      If Me.txtFile.Enabled = True Then
         Me.txtFile.Enabled = False
      Else
         Me.txtFile.Enabled = True
      End If
   End Sub

   Private Sub Label1_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles Label1.Click
      If Me.txtCartella.Enabled = True Then
         Me.txtCartella.Enabled = False
      Else
         Me.txtCartella.Enabled = True
      End If
   End Sub

   Private Sub CSVIngleseCSVItalianoToolStripMenuItem_Click( _
           ByVal sender As System.Object, ByVal e As System.EventArgs) _
           Handles CSVIngleseCSVItalianoToolStripMenuItem.Click
      Me.txtTestoConvertito.Text = Me.txtTestoDaConvertire.Text
      Me.txtTestoConvertito.Text = Me.txtTestoConvertito.Text.Replace(",", ";")
      Me.txtTestoConvertito.Text = Me.txtTestoConvertito.Text.Replace(".", ",")
      Me.txtTestoConvertito.Text = Me.txtTestoConvertito.Text.Replace( _
           System.Environment.NewLine, System.Environment.NewLine)
   End Sub

   Private Sub CSVItalianoCSVIngleseToolStripMenuItem_Click( _ 
           ByVal sender As System.Object, ByVal e As System.EventArgs) _
           Handles CSVItalianoCSVIngleseToolStripMenuItem.Click
      Me.txtTestoConvertito.Text = Me.txtTestoDaConvertire.Text
      Me.txtTestoConvertito.Text = Me.txtTestoConvertito.Text.Replace(",", ".")
      Me.txtTestoConvertito.Text = Me.txtTestoConvertito.Text.Replace(";", ",")
   End Sub

    Private Sub EsciToolStripMenuItem_Click(ByVal sender _
             As System.Object, ByVal e As System.EventArgs) _
             Handles EsciToolStripMenuItem.Click
        Me.Close()
    End Sub

    Private Sub ChiudiFileToolStripMenuItem_Click(ByVal sender _
             As System.Object, ByVal e As System.EventArgs) _
             Handles ChiudiFileToolStripMenuItem.Click
        Me.txtTestoDaConvertire.Text = ""
        Me.txtTestoConvertito.Text = ""
    End Sub
End Class

Il punto chiave, è nei metodi CSVIngleseCSVItalianoToolstripMenuItem e nell’opposto CSVItalianoCSVIngleseToolStripMenuItem.

In questi metodi emerge chiaramente che la conversione “inversa” avviene non solo sostituendo i due valori da sostituire, nell’ambito della stessa istruzione di conversione, ma anche scambiando le due istruzioni che utilizzano il metodo Replace. Solo così, infatti, è possibile effettuare una conversione corretta ed eventualmente ripetere la conversione per ripristinare la situazione precedente.

Pubblicato il 23 gennaio 2009 su Novità. Aggiungi ai preferiti il collegamento . 15 commenti.

  1. Ciao,
    interessante questo programmino, ma mi chiedo perchè sprecare tutte queste energie quando Excel, di per se, ci offre già la soluzione al problema.

    Leggendo la tua premessa, facendo un doppio click sul file CSV, tutte le informazioni contenute nel csv sono nelle celle della colonna A, per cui A1 contiene tutta la prima riga, A2 tutta la seconda, A3 la terza…. An l’ennesima
    Se è così ed Excel è su una macchina impostata con lingua italiana ( “;” come separatore di campo, “,” come separatore decimale, “.” come separatore delle migliaia) ed il csv è formattato nello stile “inglese”. PEr cui, il csv è fatto più o meno così:

    Nome,Cognome,Eta,valore
    Francesco,Giossi,36,3.50
    Pippo,Rossi,25,5.90
    Pluto,Bianchi,30,5.80

    Se lo apro con Excel su una macchina con impostazioni in italiano, ottengo come risultato che excel mi posiziona nella cella A1 la prima riga, nella cella A2 la seconda riga e nella cella A3 la terza riga.
    Questo avviene con qualunque versione di Excel si abbia a che fare. 2003, 2000, xp, 97, ec…

    Per ottenere quello che ottieni con il tuo programma, basta fare:
    – Selezionare la colonna A (TUTTA LA COLONNA, quindi premere col mouse sulla intestazione di colonna A)
    – Con Excel 2007, selezionare il tab DATI
    – Premere “Testo in colonne”
    – Nella prima schermata dello wizard premere “Avanti”
    – Nella seconda, selezionare “Virgola” nel frame “Delimitatori” (si può togliere Tabulazione, ma anche no, viene ignorato) e premere “Avanti”
    – Nella terza, premere il tasto “Avanzate”
    – Impostare come separatore decimale il separatore decimale usato nel csv (nell’esempio che riport sopra, inserire “.” senza doppi apici)
    – Stessa cosa per il separatore delle migliaia, per cui inserire “,” senza doppi apici.
    – Premere Ok
    – Premere Fine.

    Et voilà!
    Ecco qui il nostro csv formattato in Excel come piace a noi (ed anche ad Excel).

    In questo modo non devi passare da programmi terzi o manipolare il file originale.

    Spero di essere stato chiaro e di una qualche utilità.

    ciao

    Francesco

    Mi piace

  2. Grazie Francesco, ma la risposta alla tua domanda iniziale: “mi chiedo perchè sprecare tutte queste energie quando Excel, di per se, ci offre già la soluzione al problema”.
    Immagina di avere decine di file .csv e di dover fare le operazioni che hai elencato per ogni file: pensi che non sia sufficiente questo per giustificare una soluzione “programmatica”? 😉
    Ciao!

    Mi piace

    • Ciao Mario,
      credo che sia sufficiente sì, ma in quel caso procederei con lo sfruttare le automazioni di Excel e ci infilerei una bella macro che faccia le operazioni che ho elencato.
      Dipende sempre da cosa si deve fare: esistono scenari in cui è probabile che sia meglio tritare i .csv prima di farli elaborare da Excel (pre-process) piuttosto che procedere con una soluzione in tempo reale.
      Avendo a che fare da diverso tempo con file csv, in ambienti non eterogenei, con pc su cui vengono montate versioni diverse di Office, su macchine windows 2000, xp e Vista in italiano, inglese e tedesco, la soluzione del pre-trita mi ha sempre portato a grandi problemi.

      In tutto questo, mamma MS ci mette del suo.
      Prova questo:
      – Apri Excel e crea una piccola tabellina di dati
      – Menu File, Salva con nome… e salva il tutto come csv (es. cartella1.csv)
      – Crea una nuova sheet Excel, crea una tabellina ed adesso registra una macro. La macro deve fare esattamente quello che hai fatto prima, ovvero salvare il file in formato csv.
      Il codice creato sarà questo


      ActiveWorkbook.SaveAs Filename:= _
      "C:\dovevuoi\cartella2.csv", FileFormat:=xlCSV

      – Riutilizza questo codice per salvare un terzo file csv (devi eseguire il codice)

      Ora, apri i tre file con notepad (o equivalente) e fatti insieme a me una bella risata!😀
      Non dovrebbe essere la stessa cosa? hmm, pare di no!
      Questo per dire che nulla è come sembra.

      ciao

      Mi piace

  3. ciao ho appena risolto il vostro problema in maniera semplice. Basta aggiungere il comando local:=true

    ActiveWorkbook.SaveAs Filename:=””C:\dovevuoi\cartella2.csv”, FileFormat:= _
    xlCSV, local:=True

    Mi piace

    • geniale, mai visto!

      grazie :p

      Mi piace

    • Luca, dimentichi il presupposto da cui sono partito con il mio articolo: si tratta di file .csv creati da altri con formati diversi da quello utilizzabile dal proprio PC. In ufficio è una cosa che ci è capitata spesso: apri il file .csv e Excel apre il file attribuendo ciascuna riga alla prima cella di ogni riga, senza separare le varie colonne.
      Ecco quindi che il trucchetto (che bisogna necessariamente utilizzare in Excel e scrivere all’interno di ogni file .xls che si crea, quindi manualmente) non funziona.
      Inserire il comando che proponi significa partire già da un file Excel in formato .xls.
      Diciamo che in questa serie di commenti si sono aggiunte problematiche che non c’entravano più di tanto con l’articolo iniziale 🙂
      Grazie comunque per la proposta di comando VBA che potrà essere utile in altri scenari.

      Mi piace

  4. @ Francesco Giossi: si, ma la questione non cambia. La macro che ha proposto Luca serve per salvare i dati contenuti in un foglio Excel in un file formato CSV “ben formato”.

    Il mio articolo invece parte da un altro presupposto: ricevo un file in formato CSV “mal formato”, nel senso che se lo apro con Excel non mi divide i dati nelle varie colonne ma mi mette tutto nella prima colonna, perché invece di avere il separatore utilizzato di solito (;) c’è la virgola.

    Cosa faccio per risolvere, cioè per aprire ‘sto benedetto file CSV e salvarlo in un file CSV “ben formato” caricabile in Excel?
    O faccio tutto manualmente (ma non si può pretendere di farlo manualmente per decine e decine di file .CSV), oppure automatizzo tutto con un programma Visual Basic.

    A quel punto si può creare un ciclo che prende tutti i CSV, ciclando nella directory in cui sono contenuti, e li trasforma in un CSV nel formato che ci serve.

    In buona sostanza: cosa me ne faccio di una macro Excel, se non riesco ad aprire i dati del file CSV in modo corretto? E soprattutto a cosa mi serve una macro per fare l’operazione in manuale (o semi-manuale, se vuoi) per decine, centinaia di volte?

    Apprezzo lo sforzo di trovare un’altra soluzione, ma bisogna partire dallo stesso contesto, non si può uscire dal seminato. Se cambia il contesto iniziale, è un problema diverso da risolvere e quindi è diversa anche la soluzione.

    Mi piace

  5. Per carità, ognuno è libero di esprimersi liberamente (nei limiti del lecito, ovviamente), ma mi piacerebbe che non si mescolassero “situazioni diverse”, dato che poi il thread potrebbe diventare di difficile collocazione, rispetto all’articolo iniziale.

    Tuttavia il thread sta diventando quasi un forum (o addirittura una chat), quindi vi consiglierei di aprire una discussione sull’appropriato forum in http://www.dotnetwork.it, dove possiamo continuare questa discussione, magari con una spiegazione iniziale, altrimenti chi arriva non capisce nulla!

    Mi piace

  6. infatti io non ci ho capito nulla e sono un emerito ignorante! se magari tutto ciò che avete scritto lo possiate tradurre in termini più semplici forse potrei riuscire a tradurre un intero gioco dall’italiano all’inglese😀

    Mi piace

  7. Grazie Mario e Grazie Luca per il Local True!!!!

    Mi piace

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: