537 Stimmen

Umgang mit Kommas in einer CSV-Datei

Ich bin auf der Suche nach Vorschlägen, wie eine CSV-Datei zu behandeln ist, die von unseren Kunden erstellt und dann hochgeladen wird und die möglicherweise ein Komma in einem Wert enthält, z. B. einen Firmennamen.

Einige der Ideen, die wir in Betracht ziehen, sind: Bezeichner in Anführungszeichen (Wert "," Werte ", "usw.) oder die Verwendung eines | anstelle eines Kommas. Das größte Problem ist, dass wir es einfach machen müssen, sonst wird der Kunde es nicht tun.

455voto

Corey Trager Punkte 21897

Es gibt sogar eine Spezifikation für das CSV-Format, RFC 4180 und wie man mit Kommas umgeht:

Felder, die Zeilenumbrüche (CRLF), doppelte Anführungszeichen und Kommas enthalten, sollten in doppelte Anführungszeichen gesetzt werden.

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

Also, um Werte zu haben foo y bar,baz tun Sie dies:

foo,"bar,baz"

Eine weitere wichtige Anforderung, die zu berücksichtigen ist (ebenfalls aus der Spezifikation):

Wenn Felder in doppelte Anführungszeichen gesetzt werden, dann wird ein doppeltes Anführungszeichen innerhalb eines Feldes durch ein vorangestelltes Anführungszeichen ein weiteres doppeltes Anführungszeichen vorangestellt werden. Zum Beispiel:

"aaa","b""bb","ccc"

238voto

harpo Punkte 39680

Wie bereits gesagt wurde, müssen Sie Werte, die Anführungszeichen enthalten, ausblenden. Hier ist ein kleiner CSV-Reader in C, der Anführungszeichen unterstützt, einschließlich eingebetteter Anführungszeichen und Zeilenumbrüche.

Übrigens ist dies ein Unit-getesteter Code. Ich bin es jetzt posten, weil diese Frage zu kommen scheint eine Menge und andere möglicherweise nicht wollen, eine ganze Bibliothek, wenn einfache CSV-Unterstützung zu tun.

Sie können es wie folgt verwenden:

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();
    }
}

Hier sind die Klassen. Beachten Sie, dass Sie die Csv.Escape Funktion, um auch gültige CSV-Dateien zu schreiben.

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' };
}

82voto

Robert Gamble Punkte 101657

Im CSV-Format werden Werte durch Kommas getrennt. Werte, die Wagenrückläufe, Zeilenumbrüche, Kommas oder doppelte Anführungszeichen enthalten, sind von doppelten Anführungszeichen umgeben. Werte, die doppelte Anführungszeichen enthalten, werden in Anführungszeichen gesetzt, und jedes wörtliche Anführungszeichen wird durch ein unmittelbar vorangehendes Anführungszeichen ersetzt: Zum Beispiel, die 3 Werte:

test
list, of, items
"go" he said

würde verschlüsselt werden als:

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

Jedes Feld kann in Anführungszeichen gesetzt werden, aber nur Felder, die Kommas, CR/NL oder Anführungszeichen enthalten muss zitiert werden.

Es gibt keine echte Standard für das CSV-Format, aber fast alle Anwendungen folgen den dokumentierten Konventionen aquí . Der RFC, der an anderer Stelle erwähnt wurde, ist kein Standard für CSV, sondern ein RFC für die Verwendung von CSV innerhalb von MIME und enthält einige unkonventionelle und unnötige Einschränkungen, die ihn außerhalb von MIME unbrauchbar machen.

Ein Problem, das viele CSV-Module, die ich gesehen habe, nicht berücksichtigen, ist die Tatsache, dass mehrere Zeilen in einem einzigen Feld kodiert werden können, was bedeutet, dass Sie nicht davon ausgehen können, dass jede Zeile ein separater Datensatz ist. Sie müssen entweder keine Zeilenumbrüche in Ihren Daten zulassen oder darauf vorbereitet sein, dies zu behandeln.

43voto

Joe Phillips Punkte 46741

Setzen Sie Zeichenketten in Anführungszeichen. Das ist im Allgemeinen was Excel macht .

Ala Eli,

ein Anführungszeichen wird als zwei doppelte Anführungszeichen. z.B.. "test1","foo""bar","test2"

12voto

Adam Jaskiewicz Punkte 10844

Sie können die Felder in Anführungszeichen setzen. Ich mag diesen Ansatz nicht, da er ein weiteres Sonderzeichen (das doppelte Anführungszeichen) hinzufügt. Definieren Sie einfach ein Escape-Zeichen (in der Regel Backslash) und verwenden Sie es überall dort, wo Sie ein Escape-Zeichen benötigen:

data,more data,more data\\, even,yet more

Sie müssen nicht versuchen, Anführungszeichen zuzuordnen, und es gibt weniger Ausnahmen zu parsen. Das vereinfacht auch Ihren Code.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X