Gestione delle virgole in un file CSV


472

Sto cercando suggerimenti su come gestire un file CSV che viene creato, quindi caricato dai nostri clienti e che può avere una virgola in un valore, come il nome di una società.

Alcune delle idee che stiamo esaminando sono: identificatori quotati (valore "," valori "," ecc.) O usando un | invece di una virgola. Il problema più grande è che dobbiamo renderlo facile, altrimenti il ​​cliente non lo farà.


il cliente lo sta scrivendo e caricando
Bob The Janitor,

1
Ecco la soluzione per gestire le virgole interne nel file CSV. visita stackoverflow.com/questions/9889225/…
Hasan Abrar il

su iOS, essenzialmente devi usare github.com/Flinesoft/CSVImporter
Fattie il

3
Nota che questo QA è vecchio. Oggi CSV significa RFC 4180 e basta .
Fattie,

Ho lo stesso identico problema, provando a totalizzare una colonna in un file CSV che è separato da virgola. Nessun problema con un comando awk. Purtroppo alcune celle possono contenere virgole (ad esempio in un indirizzo), altre celle no. Alla ricerca di una soluzione compatibile Linux ma non so da dove cominciare.
Greenage

Risposte:


223

Come altri hanno già detto, è necessario sfuggire ai valori che includono virgolette. Ecco un piccolo lettore CSV in C♯ che supporta i valori tra virgolette, inclusi virgolette incorporate e ritorni a capo.

A proposito, questo è un codice testato dall'unità. Lo sto postando ora perché questa domanda sembra sollevarsi molto e altri potrebbero non voler un'intera libreria quando lo farà il semplice supporto CSV.

Puoi usarlo come segue:

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

Ecco le lezioni. Nota che puoi usare la Csv.Escapefunzione anche per scrivere CSV validi.

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

2
Potrebbe anche essere necessario tradurre \ r \ n per la conformità di Windows, a seconda dell'applicazione.
Mandrake,

3
@NadaNaeem, ti interessa elaborare?
Harpo,

non sta contando correttamente gli elementi in una riga di file CSV, non sta trattando bene le virgole nei campi e i ritorni e i tocchi di coraggio
Nada N. Hantouli

-1 OP non specifica una lingua che sta creando il file. Se un altro programmatore viene qui alla ricerca di una soluzione in qualsiasi lingua tranne C #, non troverà una soluzione che può utilizzare in questa risposta.
Ben Leggiero,

8
@ BenC.R.Leggiero, quindi suppongo che anche tu debba sottovalutare la domanda, in quanto non risponde ai tuoi standard. Allo stato attuale, il codice equivale a un'implementazione formale di una specifica semplice e può essere facilmente tradotto in qualsiasi linguaggio comunemente usato.
Harpo,

395

Per il 2017, CSV è completamente specificato: RFC 4180.

È una specifica molto comune ed è completamente coperta da molte librerie ( esempio ).

Basta usare qualsiasi libreria CSV facilmente disponibile , vale a dire RFC 4180.


In realtà c'è una specifica per il formato CSV e come gestire le virgole:

I campi che contengono interruzioni di riga (CRLF), virgolette doppie e virgole devono essere racchiusi tra virgolette doppie.

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

Quindi, per avere valori fooe bar,baz, fai questo:

foo,"bar,baz"

Un altro requisito importante da considerare (anche dalle specifiche):

Se le virgolette doppie vengono utilizzate per racchiudere i campi, è necessario evitare una virgoletta doppia che appare all'interno di un campo precedendola con un'altra virgoletta doppia. Per esempio:

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

120
"I campi che contengono interruzioni di riga (CRLF), virgolette doppie e virgole devono essere racchiusi tra virgolette doppie."
Eli,

42
"Se le virgolette doppie vengono utilizzate per racchiudere i campi, allora una virgoletta doppia che appare all'interno di un campo deve essere sfuggita precedendola con un'altra virgoletta doppia."
C. Dragon 76,

11
Non proprio una specifica, ma probabilmente comunque utile. Dice ... "Non esistono specifiche formali che consentano un'ampia varietà di interpretazioni dei file CSV. Questa sezione documenta il formato che sembra essere seguito dalla maggior parte delle implementazioni."
Justin Clarke,

5
Inoltre, non dimenticare che, nonostante il nome, i valori CSV nella riga possono essere separati non solo da virgole, almeno su piattaforme Windows. Dipende dalle impostazioni internazionali correnti (intl.cpl nella linea di comando, "Impostazioni avanzate"), in separatore di particolare lista: System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.
lxa,

4
Si prega di inserire le informazioni pertinenti in questa risposta, oltre al collegamento, ad A) Rimuovere la maggior parte dei commenti sopra (e il mio), B) Salvare così tante persone in più rispetto al risponditore il tempo di andare in un'altra pagina e trovare il pertinente dati, C) Prevenire la rotazione del collegamento.
user66001,

76

Il formato CSV utilizza le virgole per separare i valori, i valori che contengono ritorni a capo, avanzamenti di riga, virgole o virgolette doppie sono racchiusi tra virgolette doppie. I valori che contengono virgolette doppie vengono citati e ogni citazione letterale viene ignorata da una citazione immediatamente precedente: Ad esempio, i 3 valori:

test
list, of, items
"go" he said

sarebbe codificato come:

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

Ogni campo può essere citato, ma solo i campi che contengono le virgole, CR / NL, o citazioni deve essere citato.

Non esiste uno standard reale per il formato CSV, ma quasi tutte le applicazioni seguono le convenzioni documentate qui . L'RFC menzionato altrove non è uno standard per CSV, è un RFC per l'utilizzo di CSV all'interno di MIME e contiene alcune limitazioni non convenzionali e non necessarie che lo rendono inutile al di fuori di MIME.

Un gotcha che molti moduli CSV che ho visto non soddisfa è il fatto che più righe possono essere codificate in un singolo campo, il che significa che non puoi supporre che ogni riga sia un record separato, o che sia necessario non consentire nuove righe nel proprio dati o essere pronti a gestire questo.


40

Metti le virgolette doppie attorno alle stringhe. Questo è generalmente ciò che fa Excel .

Ala Eli,

si evita una doppia virgoletta come due virgolette doppie. Ad esempio "test1", "foo" "bar", "test2"


sostanzialmente lo stesso concetto di un identificatore citato
Bob The Janitor,

1
si evita una doppia virgoletta come due virgolette doppie. Ad esempio "test1", "foo" "bar", "test2"
Eli,

Mettere solo virgolette doppie attorno alla stringa non funziona quando un "è seguito immediatamente da una virgola
MondKin

9

È possibile inserire virgolette doppie nei campi. Non mi piace questo approccio, in quanto aggiunge un altro carattere speciale (la doppia citazione). Basta definire un personaggio di escape (di solito una barra rovesciata) e usarlo ovunque sia necessario per sfuggire a qualcosa:

dati, più dati, più dati \, anche, ancora di più

Non devi cercare di abbinare le virgolette e hai meno eccezioni da analizzare. Questo semplifica anche il tuo codice.


3
Veloce e sporco ma non funziona se in realtà hai una voce che contiene "\",
Sarp Kaya

1
Sarp, ecco perché un doppio \\ è una barra rovesciata, poiché ora diventa un altro personaggio speciale.
Grungondola,

1
Funziona, ma non è CSV. È un DSV .
TRiG

8

C'è una libreria disponibile tramite nuget per gestire praticamente qualsiasi CSV ben formato (.net) - CsvHelper

Esempio per mappare una classe:

var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();

Esempio per leggere singoli campi:

var csv = new CsvReader( textReader );
while( csv.Read() )
{
    var intField = csv.GetField<int>( 0 );
    var stringField = csv.GetField<string>( 1 );
    var boolField = csv.GetField<bool>( "HeaderName" );
}

Consentire al client di guidare il formato del file:
, è il delimitatore di campo standard, "è il valore standard utilizzato per sfuggire ai campi che contengono un delimitatore, un preventivo o un finale di riga.

Per utilizzare (ad esempio) #per i campi e 'per la fuga:

var csv = new CsvReader( textReader );
csv.Configuration.Delimiter = "#";
csv.Configuration.Quote = ''';
// read the file however meets your needs

Più documentazione


3
Sarebbe preferibile includere un esempio di come utilizzare la CsvHelperlibreria per risolvere il problema del PO.
George Stocker,

Perché quasi tutto in .Net deve diventare un "aiutante" ... la parola è quasi insignificante ... come "Manager".
bytedev,

5

Come menzionato nel mio commento alla risposta di Harpo, la sua soluzione è buona e funziona nella maggior parte dei casi, tuttavia in alcuni scenari quando le virgole sono direttamente adiacenti tra loro non riesce a dividersi sulle virgole.

Ciò è dovuto al fatto che la stringa Regex si comporta inaspettatamente come una stringa vertabim. Al fine di ottenere questo comportamento corretto, tutti i "caratteri nella stringa regex devono essere salvati manualmente senza usare la escape vertabim.

Vale a dire. Il regex dovrebbe essere questo usando escape manuali:

",(?=(?:[^\"\"]*\"\"[^\"\"]*\"\")*(?![^\"\"]*\"\"))"

che si traduce in ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"

Quando si utilizza una stringa vertabim, @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"si comporta come segue, come si può vedere se si esegue il debug di regex:

",(?=(?:[^"]*"[^"]*")*(?![^"]*"))"

Quindi, in sintesi, raccomando la soluzione di harpo, ma fai attenzione a questo piccolo gotcha!

Ho incluso nel CsvReader un po 'di sicurezza opzionale per avvisarti se si verifica questo errore (se hai un numero di colonne noto):

if (_expectedDataLength > 0 && values.Length != _expectedDataLength) 
throw new DataLengthException(string.Format("Expected {0} columns when splitting csv, got {1}", _expectedDataLength, values.Length));

Questo può essere iniettato tramite il costruttore:

public CsvReader(string fileName, int expectedDataLength = 0) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
    _expectedDataLength = expectedDataLength;
}

Come gestiresti la riga di intestazione? sto cercando di mappare il CSV su oggetti C # che sono di tutti i tipi, ma la riga di intestazione lo interrompe perché sono tutte stringhe ...
tCoe

Non è [^""]lo stesso di [^"]? La duplicazione di un personaggio all'interno di una specifica della classe di caratteri è ridondante, giusto?
Minh Tran,

4

Aggiungi un riferimento a Microsoft.VisualBasic (sì, dice VisualBasic ma funziona anche in C # - ricorda che alla fine è tutto solo IL).

Utilizzare la Microsoft.VisualBasic.FileIO.TextFieldParserclasse per analizzare il file CSV Ecco il codice di esempio:

 Dim parser As TextFieldParser = New TextFieldParser("C:\mar0112.csv")
 parser.TextFieldType = FieldType.Delimited
 parser.SetDelimiters(",")      

   While Not parser.EndOfData         
      'Processing row             
      Dim fields() As String = parser.ReadFields         
      For Each field As String In fields             
         'TODO: Process field                   

      Next      
      parser.Close()
   End While 

Sì, questa è una classe molto utile in uno spazio dei nomi un po 'sfortunato ;-). Per rispondere alla domanda originale, tuttavia, dovresti anche impostare parser.HasFieldsEnclosedInQuotes = true;e il file di input dovrebbe racchiudere i campi che contengono virgole tra virgolette secondo le specifiche CSV - Excel lo fa già.
Christopher King,


4

Nel caso in cui ti trovi su un sistema * nix , accedi ased e ci possano essere una o più virgole indesiderate solo in un campo specifico del tuo CSV, puoi usare il seguente one-liner per racchiuderle "come Sezione RFC4180 2 propone:

sed -r 's/([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*)/\1"\2"\3/' inputfile

A seconda del campo in cui potrebbero trovarsi le virgole indesiderate, è necessario modificare / estendere i gruppi di acquisizione della regex (e della sostituzione).
L'esempio sopra racchiuderà il quarto campo (su sei) tra virgolette.

inserisci qui la descrizione dell'immagine

In combinazione con l' --in-placeopzione -puoi applicare queste modifiche direttamente al file.

Per "costruire" la giusta regex, c'è un semplice principio da seguire:

  1. Per ogni campo nel tuo CSV che precede il campo con le virgole indesiderate, ne scrivi una [^,]*,e le mette tutte insieme in un gruppo di acquisizione.
  2. Per il campo che contiene le virgole indesiderate che scrivi (.*).
  3. Per ogni campo dopo il campo con le virgole indesiderate ne scrivi una ,.* e le metti tutte insieme in un gruppo di acquisizione.

Ecco una breve panoramica di diverse possibili regex / sostituzioni a seconda del campo specifico. Se non indicato, la sostituzione è \1"\2"\3.

([^,]*)(,.*)                     #first field, regex
"\1"\2                           #first field, substitution

(.*,)([^,]*)                     #last field, regex
\1"\2"                           #last field, substitution


([^,]*,)(.*)(,.*,.*,.*)          #second field (out of five fields)
([^,]*,[^,]*,)(.*)(,.*)          #third field (out of four fields)
([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*) #fourth field (out of six fields)

Se si desidera rimuovere le virgole indesiderate con sedanziché racchiuderle tra virgolette, fare riferimento a questa risposta .


3

Se desideri reinventare la ruota, potrebbe essere utile quanto segue:

public static IEnumerable<string> SplitCSV(string line)
{
    var s = new StringBuilder();
    bool escaped = false, inQuotes = false;
    foreach (char c in line)
    {
        if (c == ',' && !inQuotes)
        {
            yield return s.ToString();
            s.Clear();
        }
        else if (c == '\\' && !escaped)
        {
            escaped = true;
        }
        else if (c == '"' && !escaped)
        {
            inQuotes = !inQuotes;
        }
        else
        {
            escaped = false;
            s.Append(c);
        }
    }
    yield return s.ToString();
}

3

In Europa abbiamo questo problema prima di questa domanda. In Europa usiamo tutta una virgola per un punto decimale. Vedi questi numeri di seguito:

| American      | Europe        |
| ------------- | ------------- |
| 0.5           | 0,5           |
| 3.14159265359 | 3,14159265359 |
| 17.54         | 17,54         |
| 175,186.15    | 175.186,15    |

Quindi non è possibile utilizzare il separatore virgola per i file CSV. Per questo motivo, i file CSV in Europa sono separati da un punto e virgola ( ;) .

Programmi come Microsoft Excel possono leggere i file con un punto e virgola ed è possibile passare dal separatore. Puoi anche usare una tab ( \t) come separatore. Vedi questa risposta da Supper User .


2

Se sei interessato a un esercizio più educativo su come analizzare i file in generale (usando CSV come esempio), puoi leggere questo articolo di Julian Bucknall. Mi piace l'articolo perché suddivide le cose in problemi molto più piccoli che sono molto meno insormontabili. Prima crei una grammatica e, una volta che hai una buona grammatica, è un processo relativamente semplice e metodico per convertire la grammatica in codice.

L'articolo usa C # e ha un link in fondo per scaricare il codice.


1

Ecco una piccola soluzione ordinata:

È invece possibile utilizzare un segno numerico inferiore greco (U + 0375)

Sembra così ͵

L'uso di questo metodo consente di risparmiare anche molte risorse ...


1

Basta usare SoftCircuits.CsvParser su NuGet. Gestirà tutti quei dettagli per te e gestirà in modo efficiente file di grandi dimensioni. E, se necessario, può persino importare / esportare oggetti mappando le colonne sulle proprietà degli oggetti. Inoltre, i miei test hanno dimostrato che è in media quasi 4 volte più veloce del popolare CsvHelper.


0

Dato che si tratta di pratiche generali, partiamo dalle regole empiriche:

  1. Non usare CSV, usa XML con una libreria per leggere e scrivere invece il file xml.

  2. Se è necessario utilizzare CSV. Fallo correttamente e usa una libreria gratuita per analizzare e archiviare i file CSV.

Per giustificare 1), la maggior parte dei parser CSV non sono consapevoli della codifica, quindi se non hai a che fare con US-ASCII stai chiedendo problemi. Ad esempio, Excel 2002 memorizza il CSV nella codifica locale senza alcuna nota sulla codifica. Lo standard CSV non è ampiamente adottato :(. D'altro canto lo standard xml è ben adottato e gestisce abbastanza bene le codifiche.

Per giustificare 2), ci sono tonnellate di parser CSV in circolazione per quasi tutte le lingue, quindi non è necessario reinventare la ruota anche se le soluzioni sembrano piuttosto semplici.

Per citarne alcuni:

  • per python usa build nel modulo csv

  • per il controllo perl CPAN e Text :: CSV

  • per php usa build nelle funzioni fgetcsv / fputcsv

  • per la libreria SuperCVS di Java Check

In realtà non è necessario implementarlo manualmente se non si intende analizzarlo su un dispositivo incorporato.


12
XML non è sempre la risposta. CSV è il formato giusto per il lavoro quando hai molti dati densi e tabulari (ad esempio un foglio di calcolo). Questi tag introducono un sacco di sovraccarico e se ogni riga ha un formato identico, non è necessario essere espliciti su ciò che rappresenta ogni valore. XML è ottimo quando si hanno dati gerarchici complicati o record con campi opzionali. Non è sempre così.
Adam Jaskiewicz,

In teoria i "tag" introducono un po 'di sovraccarico, ma non riesco a pensare a nessuna applicazione di vita reale in cui inizia a essere un problema. Hai qualche esempio pratico? Per lavorare sui dati si dovrebbe usare un database invece di CSV. se parliamo di serializzazione dei dati (backup, interscambio di dati), importerà se l'analisi richiede una settimana anziché 5 giorni?
Piotr Czapla,

2
Fondamentalmente, qualsiasi situazione in cui hai dati che sono meglio rappresentati da una tabella. Supponi di avere dati provenienti da una dozzina di sensori diversi che campionerai ogni tanto, e in quel momento registri il timestamp e il valore di ciascuno dei sensori. Ogni record è identico: timestamp, sensor0, sensor1, ... sensor11. XML è ottimo per rappresentare dati complessi e irregolari, ma è un formato piuttosto pesante che non si adatta a ogni singola situazione. BACIO
Adam Jaskiewicz,

10
Alcune persone vedono un problema e dicono "Lo so, userò XML!" Ora hanno due problemi.
Adam Jaskiewicz,

Sono totalmente d'accordo sul fatto che XML non è una risposta per tutto. Soprattutto non è adatto come sostituzione del database né per i file di configurazione. Ma qui la domanda riguardava l'interscambio di dati per cui è stato progettato XML.
Piotr Czapla,

0

Puoi leggere il file CSV in questo modo.

questo fa uso di divisioni e si occupa degli spazi.

ArrayList List = new ArrayList();
static ServerSocket Server;
static Socket socket;
static ArrayList<Object> list = new ArrayList<Object>();


public static void ReadFromXcel() throws FileNotFoundException
{   
    File f = new File("Book.csv");
    Scanner in = new Scanner(f);
    int count  =0;
    String[] date;
    String[] name;
    String[] Temp = new String[10];
    String[] Temp2 = new String[10];
    String[] numbers;
    ArrayList<String[]> List = new ArrayList<String[]>();
    HashMap m = new HashMap();

         in.nextLine();
         date = in.nextLine().split(",");
         name = in.nextLine().split(",");
         numbers = in.nextLine().split(",");
         while(in.hasNext())
         {
             String[] one = in.nextLine().split(",");
             List.add(one);
         }
         int xount = 0;
         //Making sure the lines don't start with a blank
         for(int y = 0; y<= date.length-1; y++)
         {
             if(!date[y].equals(""))
             {   
                 Temp[xount] = date[y];
                 Temp2[xount] = name[y];
                 xount++;
             }
         }

         date = Temp;
         name =Temp2;
         int counter = 0;
         while(counter < List.size())
         {
             String[] list = List.get(counter);
             String sNo = list[0];
             String Surname = list[1];
             String Name = list[2];
             for(int x = 3; x < list.length; x++)
             {           
                 m.put(numbers[x], list[x]);
             }
            Object newOne = new newOne(sNo, Name, Surname, m, false);
             StudentList.add(s);
             System.out.println(s.sNo);
             counter++;
         }

0

Innanzitutto, chiediamoci "Perché sentiamo il bisogno di gestire le virgole in modo diverso per i file CSV?"

Per me, la risposta è "Perché quando esporto i dati in un file CSV, le virgole in un campo scompaiono e il mio campo viene separato in più campi in cui le virgole compaiono nei dati originali". (Questo perché la virgola è il carattere separatore di campo CSV.)

A seconda della situazione, i punti e virgola possono anche essere utilizzati come separatori di campo CSV.

Dati i miei requisiti, posso usare un carattere, ad esempio un singolo segno di virgolette basso 9, che assomiglia a una virgola.

Quindi, ecco come puoi farlo in Go:

// Replace special CSV characters with single low-9 quotation mark
func Scrub(a interface{}) string {
    s := fmt.Sprint(a)
    s = strings.Replace(s, ",", "‚", -1)
    s = strings.Replace(s, ";", "‚", -1)
    return s
}

Il secondo carattere alla virgola nella funzione Sostituisci è 8218 decimale.

Tenere presente che se si dispone di client che potrebbero disporre di lettori di testo solo ASCII, questo carattere decima 8218 non sembrerà una virgola. Se questo è il tuo caso, allora consiglierei di circondare il campo con la virgola (o punto e virgola) tra virgolette doppie per RFC 4128: https://tools.ietf.org/html/rfc4180


0

Generalmente codifico URL i campi che possono contenere virgole o caratteri speciali. E quindi decodificarlo quando viene utilizzato / visualizzato su qualsiasi supporto visivo.

(le virgole diventano% 2C)

Ogni lingua dovrebbe avere metodi per codificare URL e decodificare stringhe.

ad esempio, in Java

URLEncoder.encode(myString,"UTF-8"); //to encode
URLDecoder.decode(myEncodedstring, "UTF-8"); //to decode

So che questa è una soluzione molto generale e potrebbe non essere ideale per situazioni in cui l'utente desidera visualizzare manualmente il contenuto del file CSV.


0

Di solito lo faccio nei miei file CSV analizzando le routine. Supponiamo che la variabile 'line' sia una riga all'interno di un file CSV e che tutti i valori delle colonne siano racchiusi tra virgolette doppie. Dopo l'esecuzione delle due righe seguenti, otterrai le colonne CSV nella raccolta "valori".

// The below two lines will split the columns as well as trim the DBOULE QUOTES around values but NOT within them
    string trimmedLine = line.Trim(new char[] { '\"' });
    List<string> values = trimmedLine.Split(new string[] { "\",\"" }, StringSplitOptions.None).ToList();

1
Perché il mio codice non viene mai visualizzato in più colori su StackOverflow? Rientro di quattro spazi.
user1451111


0

La soluzione più semplice che ho trovato è quella che LibreOffice usa:

  1. Sostituisci tutto letterale "con
  2. Metti le virgolette doppie attorno alla tua stringa

Puoi anche usare quello usato da Excel:

  1. Sostituisci tutto letterale "con""
  2. Metti le virgolette doppie attorno alla tua stringa

Si noti che altre persone consigliano di eseguire solo il passaggio 2 sopra, ma che non funziona con le linee in cui a "è seguita da a ,, come in un CSV in cui si desidera avere una singola colonna con la stringa hello",world, come diceva il CSV:

"hello",world"

Che viene interpretato come una riga con due colonne: helloeworld"


1
Secondo le regole standard, qualsiasi campo contenente il carattere diviso o la citazione è racchiuso tra virgolette e le virgolette all'interno che sono raddoppiate, quindi non c'è problema. Il tuo hello",worldcampo dovrebbe semplicemente essere salvato come "hello"",world", che può essere analizzato correttamente al 100%.
Nyerguds,

0
    public static IEnumerable<string> LineSplitter(this string line, char 
         separator, char skip = '"')
    {
        var fieldStart = 0;
        for (var i = 0; i < line.Length; i++)
        {
            if (line[i] == separator)
            {
                yield return line.Substring(fieldStart, i - fieldStart);
                fieldStart = i + 1;
            }
            else if (i == line.Length - 1)
            {
                yield return line.Substring(fieldStart, i - fieldStart + 1);
                fieldStart = i + 1;
            }

            if (line[i] == '"')
                for (i++; i < line.Length && line[i] != skip; i++) { }
        }

        if (line[line.Length - 1] == separator)
        {
            yield return string.Empty;
        }
    }

0

Ho usato la libreria Csvreader ma usando quello ho ottenuto i dati esplodendo dalla virgola (,) nel valore della colonna.

Quindi, se si desidera inserire i dati del file CSV che contiene la virgola (,) nella maggior parte dei valori delle colonne, è possibile utilizzare la funzione seguente. Link autore => https://gist.github.com/jaywilliams/385876

function csv_to_array($filename='', $delimiter=',')
{
    if(!file_exists($filename) || !is_readable($filename))
        return FALSE;

    $header = NULL;
    $data = array();
    if (($handle = fopen($filename, 'r')) !== FALSE)
    {
        while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
        {
            if(!$header)
                $header = $row;
            else
                $data[] = array_combine($header, $row);
        }
        fclose($handle);
    }
    return $data;
}

0

Ho usato la libreria papaParse per analizzare il file CSV e avere le coppie chiave-valore (chiave / intestazione / prima riga del valore-file CSV).

ecco un esempio che uso:

https://codesandbox.io/embed/llqmrp96pm

contiene il file dummy.csv per avere la demo di analisi CSV.

L'ho usato all'interno di ReactJS anche se è facile e semplice replicarlo in un'app scritta con qualsiasi lingua.


0

Un esempio potrebbe aiutare a mostrare come le virgole possono essere visualizzate in un file .csv. Crea un semplice file di testo come segue:

Salvare questo file di testo come file di testo con il suffisso ".csv" e aprirlo con Excel 2000 da Windows 10.

aa, bb, cc, d; d "Nella presentazione del foglio di calcolo, la riga in basso dovrebbe apparire come la riga in alto, tranne che in basso mostra una virgola visualizzata anziché un punto e virgola tra le d." aa, bb, cc, "d, d", funziona anche in Excel

aa, bb, cc, "d, d", funziona anche in Excel 2000 aa, bb, cc, "d, d", funziona anche in Excel 2000 aa, bb, cc, "d, d", funziona anche in Excel 2000

aa, bb, cc, "d, d", questo errore in Excel 2000 a causa dello spazio belore la prima citazione aa, bb, cc, "d, d", Questo errore in Excel 2000 a causa dello spazio belore della prima citazione aa, bb, cc, "d, d", questo non riesce in Excel 2000 a causa dello spazio belore della prima citazione

aa, bb, cc, "d, d", funziona anche in Excel 2000 anche con spazi prima e dopo la seconda citazione. aa, bb, cc, "d, d", funziona anche in Excel 2000 anche con spazi prima e dopo la seconda citazione. aa, bb, cc, "d, d", funziona anche in Excel 2000 anche con spazi prima e dopo la seconda citazione.

Regola: se si desidera visualizzare una virgola in una cella (campo) di un file .csv: "Iniziare e terminare il campo con virgolette doppie, ma evitare spazi bianchi prima della prima virgoletta"


-1

Penso che la soluzione più semplice a questo problema sia quella di avere il cliente ad aprire il CSV in Excel, quindi Ctrl + R per sostituire tutte le virgole con qualsiasi identificatore desiderato. Questo è molto facile per il cliente e richiede solo una modifica nel codice per leggere il delimitatore di tua scelta.


Chi dice che hanno Excel? In realtà chi dice che è persino un essere umano che sta caricando? ...
bytedev,

-3

Utilizzare un carattere di tabulazione (\ t) per separare i campi.


4
-1 Ottimo fino a quando qualcuno utilizza una scheda nel suo valore, quindi il tuo diritto al problema che ha la persona che ha posto la domanda. Lo scambio di un carattere delimitatore con un altro non risolverà il problema.
bytedev,

Senza senso. Le persone non possono inserire le schede nei loro input di dati. Nella maggior parte dei moduli, ciò sposta semplicemente il punto di inserimento dati nel campo successivo.
Pierre,

6
"Le persone non possono inserire le schede nel loro inserimento di dati" .... sei serio ?? A) ovviamente una persona potrebbe mettere una scheda in un campo di input B) chi dice che è una GUI da cui provengono i dati? C) chi dice che è anche un essere umano che sta inserendo i dati?
bytedev,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.