533 votes

Traitant des virgules dans un fichier CSV

Je suis à la recherche pour obtenir des suggestions sur la façon de manipuler un fichier csv qui est créé, puis téléchargées par nos clients, et qui peut avoir une virgule dans une valeur, comme un nom de société.

Certaines des idées que nous examinons sont : cité des identificateurs (valeur «, » valeurs «, » etc.) ou en utilisant un | au lieu d’une virgule. Le plus gros problème est que nous avons pour le rendre facile, ou le client ne le ferai pas.

453voto

Corey Trager Points 11334

Il n’y a effectivement une spécification de format CSV et comment gérer des virgules :

http://Tools.ietf.org/html/rfc4180

237voto

harpo Points 17399

Comme d'autres l'ont dit, vous avez besoin pour échapper à des valeurs qui incluent des citations. Voici un petit CSV reader en C♯ qui prend en charge des valeurs à la cote, y compris intégrés des citations et des retours chariot.

Par ailleurs, c'est l'unité code à tester. Je poste aujourd'hui parce que cette question semble venir d'un lot et d'autres peuvent ne pas vouloir une bibliothèque entière quand CSV simple support fera.

Vous pouvez l'utiliser comme suit:

using System;
public class test
{
    public static void Main()
    {
        using ( CsvReader reader = new CsvReader( "data.csv" ) )
        {
            foreach( string[] values in reader.RowEnumerator )
            {
                Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length );
            }
        }
        Console.ReadLine();
    }
}

Voici les classes. Notez que vous pouvez utiliser l' Csv.Escape fonction pour écrire valide CSV.

using System.IO;
using System.Text.RegularExpressions;

public sealed class CsvReader : System.IDisposable
{
    public CsvReader( string fileName ) : this( new FileStream( fileName, FileMode.Open, FileAccess.Read ) )
    {
    }

    public CsvReader( Stream stream )
    {
        __reader = new StreamReader( stream );
    }

    public System.Collections.IEnumerable RowEnumerator
    {
        get {
            if ( null == __reader )
                throw new System.ApplicationException( "I can't start reading without CSV input." );

            __rowno = 0;
            string sLine;
            string sNextLine;

            while ( null != ( sLine = __reader.ReadLine() ) )
            {
                while ( rexRunOnLine.IsMatch( sLine ) && null != ( sNextLine = __reader.ReadLine() ) )
                    sLine += "\n" + sNextLine;

                __rowno++;
                string[] values = rexCsvSplitter.Split( sLine );

                for ( int i = 0; i < values.Length; i++ )
                    values[i] = Csv.Unescape( values[i] );

                yield return values;
            }

            __reader.Close();
        }
    }

    public long RowIndex { get { return __rowno; } }

    public void Dispose()
    {
        if ( null != __reader ) __reader.Dispose();
    }

    //============================================


    private long __rowno = 0;
    private TextReader __reader;
    private static Regex rexCsvSplitter = new Regex( @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" );
    private static Regex rexRunOnLine = new Regex( @"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$" );
}

public static class Csv
{
    public static string Escape( string s )
    {
        if ( s.Contains( QUOTE ) )
            s = s.Replace( QUOTE, ESCAPED_QUOTE );

        if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 )
            s = QUOTE + s + QUOTE;

        return s;
    }

    public static string Unescape( string s )
    {
        if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) )
        {
            s = s.Substring( 1, s.Length - 2 );

            if ( s.Contains( ESCAPED_QUOTE ) )
                s = s.Replace( ESCAPED_QUOTE, QUOTE );
        }

        return s;
    }


    private const string QUOTE = "\"";
    private const string ESCAPED_QUOTE = "\"\"";
    private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' };
}

81voto

Robert Gamble Points 41984

Le format CSV utilise des virgules pour séparer les valeurs, les valeurs qui contiennent des retours chariot, des sauts de ligne, des virgules ou des guillemets doubles sont entourés par des guillemets. Des valeurs qui contiennent des guillemets doubles sont cités et chaque citation littérale est échappé par un immédiatement la citation précédente: Par exemple, les 3 valeurs:

test
list, of, items
"go" he said

serait codé comme:

test,"list, of, items","""go"" he said"

Les champs peuvent être citées, mais seuls les champs qui contiennent des virgules, CR/NL ou soumissions doivent être indiqués.

Il n'y a pas de véritable standard pour le format CSV, mais presque toutes les applications de suivre les conventions documenté ici. La RFC qui a été mentionné ailleurs n'est pas une norme pour CSV, c'est un RFC pour l'utilisation de CSV à l'intérieur de MIME et contient non conventionnelles et inutile limites qui la rendent inutile l'extérieur de MIME.

Un piège que de nombreux CSV modules que j'ai vu ne pas accueillir, c'est le fait que plusieurs lignes peuvent être codées dans un seul domaine, ce qui signifie que vous ne pouvez pas supposer que chaque ligne est un enregistrement distinct, soit vous vous permettent pas des retours à la ligne dans vos données, ou être prêt à gérer cela.

42voto

Joe Philllips Points 13616

Mettez des guillemets autour des chaînes. C’est généralement ce que Excel.

Ala Eli,

vous échapper les guillemets doubles comme deux guillemets doubles. Par exemple « test1 », « foo » « bar », « test2 »

9voto

NikolaiDante Points 2990

Il y a une bibliothèque disponible via nuget pour s’occuper de CSVs (.net) - CsvHelper

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X