1
votes

Comment puis-je analyser ce fichier CSV, car il contient plusieurs virgules, il contient 3 parties dont j'ai besoin pour récupérer des informations?

Je m'entraîne à analyser les fichiers texte et csv. J'ai un fichier csv particulier sur la sorcière que j'essaie d'analyser depuis plusieurs heures, mais je ne parviens pas à trouver la logique correcte pour le faire depuis, selon l'analyse de 19 lignes et j'ai besoin de récupérer ces informations sur les 2 premières lignes puis Je dois montrer toutes les informations ci-dessous. Le fichier csv ressemble à ceci

using System;
using System.Collections.Generic;
 using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace T_2060_ParserEstadoDeCuenta
{
 class Program
 {
    static void Main(string[] args)
    {
        Console.WriteLine("Parsing the csv file");

        List<clsEstadoCuenta> resp = new List<clsEstadoCuenta>();
        var lines = File.ReadAllLines("d:\\ztemp\\parseEstcta.csv");
        for (int i = 1; i < lines.Count(); i++)
        {
            try
            {
                /*

                 */
                var campos = lines[i].Split(',');
                clsEstadoCuenta nR = new clsEstadoCuenta();

                nR.NumeroCuenta = (String.IsNullOrEmpty(campos[1])) ? "" : campos[1];
                nR.CodigoPais = 504;
                nR.Banco = "Fichosa";
                nR.Moneda = (String.IsNullOrEmpty(campos[2])) ? "" : campos[2];
                nR.TasaCambio = 24.6;
                var tmpFecha = campos[0].Split('/');
                nR.FechaTransaccion = new DateTime(Convert.ToInt32(tmpFecha[2]), Convert.ToInt32(tmpFecha[1]), Convert.ToInt32(tmpFecha[0]));
                nR.Descripcion = (String.IsNullOrEmpty(campos[1])) ? "" : campos[1];
                nR.Referencia = (String.IsNullOrEmpty(campos[2])) ? "" : campos[2];
                nR.Debito = (String.IsNullOrEmpty(campos[4])) ? 0 : Convert.ToDouble(campos[4]);
                nR.Credito = (String.IsNullOrEmpty(campos[5])) ? 0 : Convert.ToDouble(campos[5]);
                nR.Payee = "A";




            }
            catch (Exception ex)
            {

                Console.WriteLine("error on line {0} : {1}", i, ex.Message);
                continue;
            }
        }
        Console.WriteLine("Parsing has ended, we have {0} rows \n", resp.Count);

        foreach (var item in resp)
        {

            Console.WriteLine(item.NumeroCuenta+"\t" +item.CodigoPais+"\t"+item.Banco+"t"+item.Moneda+"\t"+item.Debito);
        }
        Console.ReadLine();
    }

    class clsEstadoCuenta
    {
        private string _NumeroCuenta;

        public string NumeroCuenta
        {
            get { return _NumeroCuenta; }
            set { _NumeroCuenta = value; }
        }
        private int _CodigoPais;

        public int CodigoPais
        {
            get { return _CodigoPais; }
            set { _CodigoPais = value; }
        }

        private string _Banco;

        public string Banco
        {
            get { return _Banco; }
            set { _Banco = value; }
        }

        private string _Moneda;

        public string Moneda
        {
            get { return _Moneda; }
            set { _Moneda = value; }
        }

        private double _TasaCambio;

        public double TasaCambio
        {
            get { return _TasaCambio; }
            set { _TasaCambio = value; }
        }

        private double _Debito;

        public double Debito
        {
            get { return _Debito; }
            set { _Debito = value; }
        }

        private double _Credito;

        public double Credito
        {
            get { return _Credito; }
            set { _Credito = value; }
        }

        private DateTime _FechaTrasaccion;

        public DateTime FechaTransaccion
        {
            get { return _FechaTrasaccion; }
            set { _FechaTrasaccion = value; }
        }

        private string _Payee;

        public string Payee
        {
            get { return _Payee; }
            set { _Payee = value; }
        }

        private string _Descripcion;

        public string Descripcion
        {
            get { return _Descripcion; }
            set { _Descripcion = value; }
        }

        private string _Referencia;

        public string Referencia
        {
            get { return _Referencia; }
            set { _Referencia = value; }
        }

        private string _CodigoBancario;

        public string CodigoBancario
        {
            get { return _CodigoBancario; }
            set { _CodigoBancario = value; }
        }

        private string _Categoria;

        public string Categoria
        {
            get { return _Categoria; }
            set { _Categoria = value; }
        }

        private string _Sector;

        public string Sector
        {
            get { return _Sector; }
            set { _Sector = value; }
        }

        private double _ValorLocal;

        public double ValorLocal
        {
            get
            {
                _ValorLocal = Credito - Debito;
                return _ValorLocal;
            }
            //set { _ValorLocal = value; }
        }

        private double _ValorDolares;

        public double ValorDolares
        {
            get
            {
                _ValorDolares = ValorLocal / TasaCambio;
                return _ValorDolares;
            }
           // set { _ValorDolares = value; }
        }

        private string _NombreEmpresa;

        public string NombreEmpresa
        {
            get { return _NombreEmpresa; }
            set { _NombreEmpresa = value; }
        }

    }
  }
}

J'ai exécuté des tests et débogué pour voir le comportement et me demander; Dois-je spécifier la ligne dans laquelle je suis, pour que je récupère les informations? Si oui, comment dois-je procéder?

voici mon code:

Titular,Cuenta #,Moneda,Fecha del reporte,,
MyCompany,123654897,Dollar,26/6/2010,,
,,,,,
Períod,,,,,
From:,31/01/2010,Until:,25/06/2019,,
,,,,,
Date,Description,Númber reference,Débit,Crédit,Balance
31/01/2019,Credito por Intereses,710504251714-50398277,,132.16,"3,073.55"
8/2/2019,Depositos,S9091B19,,"74,258.74","9,722.29"
8/2/2019,ACH Debito,F1999ZV,"8,748.35",,"2,073.55"
14/02/2019,Creditos Varios,F90BRF,,"7,429.77","4,391.32"
18/02/2019,ACH Debito,FT0SMD,"4,824.77",,"3,073.55"
21/02/2019,ACH Credito,F8PH,,"8,000.98","3,673.53"
21/02/2019,Transferencia entre Cuentas,2DMFRG,"7,005.96",,"2,667.57"
22/02/2019,Pago de Comision,R2SHX,20.00,,"5,647.57"
25/02/2019,ACH Credito,FT1905,,"4,083.08","4,490.65"
25/02/2019,Transferencia entre Cuentas,FT254354,"4,437.10",,"3,053.55"
25/02/2019,ACH Credito,ASF455MZQT,,222.15,"3,675.70"
25/02/2019,Transferencia entre Cuentas,GHVF456Q1XLG,"5,536.33",,"5,453.55"


4 commentaires

Utilisez un analyseur CSV et ne réinventez pas la roue. En voici un , par exemple.


Un grand nombre de bibliothèques d'analyse CSV existent principalement parce que l'analyse des fichiers CSV est plus compliquée qu'il n'y paraît


Vous pouvez également simplifier considérablement votre code. Au lieu de chaîne privée _NumeroCuento; chaîne publique NumeroCuento {get {return _NumeroCuento; } set {_NumeroCuento = valeur; }} écrivez simplement chaîne publique NumeroCuento {get; ensemble; } (le même pour toutes vos autres propriétés).


Double possible de Analyser le fichier CSV délimité dans .NET


4 Réponses :


1
votes

Le problème est que vous essayez de séparer les cellules en fractionnant "," mais une partie des cellules contient "," char. Exemple: "9 722,29".


2 commentaires

Cela identifie correctement l'erreur. Que pourrait-on faire pour y remédier? Probablement rien à part générer les données avec un séparateur de colonne différent ou un séparateur décimal différent, non?


Le bon code est plus complexe car il peut y avoir des variantes. Exemple: '"' au milieu d'une cellule. Cellule multiligne. Cellule multiligne contenant ','. Vous pouvez trouver du code en Java traitant de cela dans github.com/etuzon/Java-CSV-API



0
votes

Utilisez un analyseur CSV qui respecte les RFC 4180 - Format commun et type MIME pour les fichiers CSV .

Il est important de comprendre que l'utilisation de guillemets doubles dans votre exemple CSV est susceptible de gérer des cas comme "74,258.74" où la virgule ne doit pas être utilisée comme délimiteur. Comme indiqué par la norme:

Chaque champ peut ou non être placé entre guillemets (cependant certains programmes, tels que Microsoft Excel, n'utilisent pas de guillemets doubles du tout). Si les champs ne sont pas entourés de guillemets, alors les guillemets doubles peuvent ne pas apparaître dans les champs. Par exemple:

  "aaa","bbb","ccc"
   zzz,yyy,xxx

Voici la page de démarrage pour la version la plus populaire parser sur NuGet .


0 commentaires


1
votes

Bien que le formatage de ce CSV ne soit pas le meilleur, car il mélange des nombres avec des virgules et des points et la séparation des champs est une virgule. Toujours est-il possible de travailler avec, il suffit d'un peu de logique pour remonter les nombres qui seront séparés par les lignes.Split (',') .

Voici l'exemple que liste les données à l'écran et ajoute les valeurs dans clsEstadoCuenta.

La logique pour monter les nombres brisés est la suivante.

    static void Main(string[] args)
    {
        ReadCsvList();

        Console.WriteLine("...");
        Console.ReadLine();
    }


    private static void ReadCsvList()
    {
        string desk = System.IO.Directory.GetParent(@"../../").FullName;
        String path = $@"{desk}\filecsv.csv";
        var csvlines = File.ReadAllLines(path);


        //build header
        var header = csvlines[1].Split(',');

        clsEstadoCuenta nR = new clsEstadoCuenta();
        nR.NumeroCuenta = (String.IsNullOrEmpty(header[1])) ? "" : header[1];
        nR.CodigoPais = 504;
        nR.Banco = "Fichosa";
        nR.Moneda = (String.IsNullOrEmpty(header[2])) ? "" : header[2];
        nR.TasaCambio = 24.6;


        //build list of data
        foreach (var lines in csvlines.Skip(7))
        {
            var campos = lines.Split(',');

            //mount line
            string newline = "";
            for (int i = 0; i < campos.Count(); i++)
            {
                //Here the numbers that were divided by the Spli (',') 
                //are reassembled and saved in their respective fields.
                if (!string.IsNullOrEmpty(campos[i]))
                {
                    if (campos[i][0] == '\"')
                    {
                        campos[i] = campos[i] + campos[i + 1];
                        campos[i + 1] = "";
                        campos[i] = campos[i].Replace("\"", "");
                    }
                }

                newline += $"{campos[i]} \t";
            }

            //puts the values in the clsEstadoCuenta
            var tmpFecha = campos[0].Split('/');
            nR.FechaTransaccion.Add(new DateTime(Convert.ToInt32(tmpFecha[2]), Convert.ToInt32(tmpFecha[1]), Convert.ToInt32(tmpFecha[0])));
            nR.Descripcion.Add(String.IsNullOrEmpty(campos[1]) ? "" : campos[1]);
            nR.Referencia.Add(String.IsNullOrEmpty(campos[2]) ? "" : campos[2]);
            nR.Debito.Add(String.IsNullOrEmpty(campos[4]) ? 0 : Convert.ToDouble(campos[4]));
            nR.Credito.Add(String.IsNullOrEmpty(campos[5]) ? 0 : Convert.ToDouble(campos[5]));
            nR.Payee.Add("A");
        }

        //I will only display on the screen in 
        //this function below, it gets cleaner code.
        ListDataCSV(nR);
    }

    private static void ListDataCSV(clsEstadoCuenta data)
    {
        Console.WriteLine("Parsing the csv file");

        Console.WriteLine($"Conta: {data.NumeroCuenta} \t Pais: {data.CodigoPais} \t Banco: {data.Banco}");
        Console.WriteLine($"Moeda: {data.Moneda} \t\t Cambio: {data.TasaCambio}");

        Console.WriteLine($"");
        Console.WriteLine($"Date \t\t Description \t\t Númber Reference \t\t Débit \t Crédit \t Balance");

        for (int i = 0; i < data.GetTransactionsNumber(); i++)
        {
            var vdata = data.FechaTransaccion[i].ToString("dd/MM/yy HH:mm");
            var vdescription = data.Descripcion[i];
            var vreference = data.Referencia[i];
            var vdebito = data.Debito[i];
            var vcredito = data.Credito[i];
            var vpayee = data.Payee[i];

            Console.WriteLine($"{vdata} \t {vdescription} \t\t {vreference} \t\t {vdebito} \t {vcredito} \t {vpayee}");
        }
    }

Lorsqu'il parcourt les champs, il vérifie celui qui est cassé et s'il l'est, il prend le reste de la valeur dans le champ suivant et joint les deux.

Voici le code complet ci-dessous. p>

class clsEstadoCuenta
{

    //you will need a builder to create the lists
    public clsEstadoCuenta()
    {
        _FechaTrasaccion = new List<DateTime>();
        _Descripcion = new List<string>();
        _Referencia = new List<string>();
        _Payee = new List<string>();
        _Debito = new List<double>();
        _Credito = new List<double>();
        _Payee = new List<string>();
    }


    //method GetTransactionsNumber() 
    //heck how many items there are in the lists below
    public int GetTransactionsNumber()
    {
        return _FechaTrasaccion.Count;
    }


    //the methods below will be List since it 
    //will receive several values
    private List<DateTime> _FechaTrasaccion;
    public List<DateTime> FechaTransaccion
    {
        get { return _FechaTrasaccion; }
        set { _FechaTrasaccion = value; }
    }

    private List<string> _Descripcion;
    public List<string> Descripcion
    {
        get { return _Descripcion; }
        set { _Descripcion = value; }
    }

    private List<string> _Referencia;
    public List<string> Referencia
    {
        get { return _Referencia; }
        set { _Referencia = value; }
    }

    private List<double> _Debito;
    public List<double> Debito
    {
        get { return _Debito; }
        set { _Debito = value; }
    }

    private List<double> _Credito;
    public List<double> Credito
    {
        get { return _Credito; }
        set { _Credito = value; }
    }

    private List<string> _Payee;
    public List<string> Payee
    {
        get { return _Payee; }
        set { _Payee = value; }
    }



    //private double _ValorLocal;
    //public double ValorLocal
    //{
    //    get
    //    {
    //        _ValorLocal = Credito - Debito;
    //        return _ValorLocal;
    //    }
    //    //set { _ValorLocal = value; }
    //}

    //private double _ValorDolares;
    //public double ValorDolares
    //{
    //    get
    //    {
    //        _ValorDolares = ValorLocal / TasaCambio;
    //        return _ValorDolares;
    //    }
    //    // set { _ValorDolares = value; }
    //}




    private string _NumeroCuenta;
    public string NumeroCuenta
    {
        get { return _NumeroCuenta; }
        set { _NumeroCuenta = value; }
    }
    private int _CodigoPais;
    public int CodigoPais
    {
        get { return _CodigoPais; }
        set { _CodigoPais = value; }
    }

    private string _Banco;
    public string Banco
    {
        get { return _Banco; }
        set { _Banco = value; }
    }

    private string _Moneda;
    public string Moneda
    {
        get { return _Moneda; }
        set { _Moneda = value; }
    }

    private double _TasaCambio;
    public double TasaCambio
    {
        get { return _TasaCambio; }
        set { _TasaCambio = value; }
    }

    private string _NombreEmpresa;
    public string NombreEmpresa
    {
        get { return _NombreEmpresa; }
        set { _NombreEmpresa = value; }
    }

    private string _CodigoBancario;
    public string CodigoBancario
    {
        get { return _CodigoBancario; }
        set { _CodigoBancario = value; }
    }

    private string _Categoria;
    public string Categoria
    {
        get { return _Categoria; }
        set { _Categoria = value; }
    }

    private string _Sector;
    public string Sector
    {
        get { return _Sector; }
        set { _Sector = value; }
    }
}

SOLUTION 2

Ce code a besoin de quelques modifications pour fonctionner correctement certains des attributs de clsStateCount.cs code> devra être List, puis yes peut être Add () tel que nR.Debito.Add()

La classe clsStateCount.cs aura besoin d'un constructeur qui crée les Lists.

    private List<DateTime> _FechaTrasaccion;
    public List<DateTime> FechaTransaccion
    {
        get { return _FechaTrasaccion; }
        set { _FechaTrasaccion = value; }
    }

Aussi la Date , Description , Numéro de référence , Les attributs Dà © bit , Crà © dit et Balance devront être List car ils recevront plusieurs données.

    public clsEstadoCuenta()
    {
        _FechaTrasaccion = new List<DateTime>();
        _Descripcion = new List<string>();
        _Referencia = new List<string>();
        _Payee = new List<string>();
        _Debito = new List<double>();
        _Credito = new List<double>();
        _Payee = new List<string>();
    }

Voici le code complet de la classe:

    static void Main(string[] args)
    {
        ReadCsv();

        Console.WriteLine("...");
        Console.ReadLine();
    }

    private static void ReadCsv()
    {
        string desk = System.IO.Directory.GetParent(@"../../").FullName;
        String path = $@"{desk}\filecsv.csv";
        var csvlines = File.ReadAllLines(path);

        Console.WriteLine("Parsing the csv file");


        //build header
        var header = csvlines[1].Split(',');

        clsEstadoCuenta nR = new clsEstadoCuenta();
        nR.NumeroCuenta = (String.IsNullOrEmpty(header[1])) ? "" : header[1];
        nR.CodigoPais = 504;
        nR.Banco = "Fichosa";
        nR.Moneda = (String.IsNullOrEmpty(header[2])) ? "" : header[2];
        nR.TasaCambio = 24.6;


        //build list of data
        foreach (var lines in csvlines.Skip(7))
        {
            var campos = lines.Split(',');

            //mount line
            string newline = "";
            for (int i = 0; i < campos.Count(); i++)
            {
                //Here the numbers that were divided by the Spli (',') 
                //are reassembled and saved in their respective fields.
                if (!string.IsNullOrEmpty(campos[i]))
                {
                    if (campos[i][0] == '\"')
                    {
                        campos[i] = campos[i] + campos[i + 1];
                        campos[i + 1] = "";
                        campos[i] = campos[i].Replace("\"","");
                    }
                }

                newline += $"{campos[i]} \t";
            }

            //puts the values in the clsEstadoCuenta
            var tmpFecha = campos[0].Split('/');
            nR.FechaTransaccion = new DateTime(Convert.ToInt32(tmpFecha[2]), Convert.ToInt32(tmpFecha[1]), Convert.ToInt32(tmpFecha[0]));
            nR.Descripcion = (String.IsNullOrEmpty(campos[1])) ? "" : campos[1];
            nR.Referencia = (String.IsNullOrEmpty(campos[2])) ? "" : campos[2];
            nR.Debito = (String.IsNullOrEmpty(campos[4])) ? 0 : Convert.ToDouble(campos[4]);
            nR.Credito = (String.IsNullOrEmpty(campos[5])) ? 0 : Convert.ToDouble(campos[5]);
            nR.Payee = "A";

            Console.WriteLine($"{newline}");
        }
    }

Déjà le code qui lit CSV et les affichages que je mets avec fonctions séparées pour faciliter la lecture.

     if (!string.IsNullOrEmpty(campos[i]))
     {
         if (campos[i][0] == '\"')
         {
             campos[i] = campos[i] + campos[i + 1];
             campos[i + 1] = "";
             campos[i] = campos[i].Replace("\"","");
         }
     }


9 commentaires

Merci Alberto pour votre aide .. a beaucoup aidé .. J'essayais votre suggestion et cela a parfaitement fonctionné. Ensuite, j'ai essayé d'implémenter une partie du code d'origine, comme en essayant d'ajouter le nR à resp et quand je fais une instruction foreach afin d'afficher les informations, il montre uniquement 1 ligne .. Je manque quelque chose?


La partie où vous listez les données brutes est configurée pour commencer la boucle sur la ligne 7 où vous avez les données. foreach (var lines dans csvlines.Skip (7))


Désolé si je n'ai pas compris votre question.


Je m'excuse si ma question n'était pas claire. J'ai une ligne de code où je crée une List resp = new List (); Après avoir analysé et enregistré toutes les informations requises, je dois enregistrer le clsEstadoCuenta nR = new clsEstadoCuenta () dans resp. Quand je fais resp.Add (nR) et que j'utilise une instruction foreach, je pensais que j'allais voir toutes les informations, mais à la place, n'obtiendrais qu'une ligne


Je le comprends ... le resp.add (nR) était au mauvais endroit


Je débogue le code ... et quand je l'exécute, il enregistre 12 lignes de données dans resp mais quand je les imprime, il montre cette ligne ////// 25/02/2019, Transferencia entre Cuentas, GHVF456Q1XLG, "5,536,33" , "5,453,55" /////// 12 fois


Je mets une Solution 2 en un coup d'œil. J'ai compris son placement ci-dessus et l'ai corrigée dans le code. @CSharpRookieEd


Merci beaucoup Alberto ... vos solutions m'ont beaucoup aidé à comprendre la logique de l'analyse. J'ai pu analyser facilement plusieurs fichiers csv délimités de différentes manières


Je suis content que cela vous ait aidé.