Lidando com vírgulas em um arquivo CSV


472

Estou procurando sugestões sobre como lidar com um arquivo csv que está sendo criado e carregado por nossos clientes e que pode ter vírgula em um valor, como o nome da empresa.

Algumas das idéias que estamos analisando são: Identificadores entre aspas (valor "," valores "," etc ") ou usar um | em vez de vírgula. O maior problema é que precisamos facilitar as coisas ou o cliente não o fará.


o cliente é escrevê-lo e enviá-lo
Bob The Janitor

1
Aqui está a solução para gerenciar dentro de commos no arquivo csv. visite stackoverflow.com/questions/9889225/…
Hasan Abrar

no iOS, essencialmente, você deve usar github.com/Flinesoft/CSVImporter
Fattie

3
Observe que esse controle de qualidade é antigo. Hoje em dia csv significa RFC 4180 e é isso.
Gordo

Eu tenho exatamente o mesmo problema, tentando totalizar uma coluna em um arquivo CSV que é separado por vírgula. Não há problema com um comando awk. Infelizmente, algumas células podem conter vírgulas (em um endereço, por exemplo), outras não. Procurando uma solução compatível com Linux, mas não sei por onde começar.
greenage 8/12/19

Respostas:


223

Como já foi dito, você precisa escapar de valores que incluem aspas. Aqui está um pequeno leitor de CSV em C♯ que suporta valores entre aspas, incluindo cotações incorporadas e retornos de carro.

A propósito, esse é um código testado por unidade. Estou postando agora porque essa pergunta parece surgir muito e outras pessoas podem não querer uma biblioteca inteira quando o suporte simples a CSV for necessário.

Você pode usá-lo da seguinte maneira:

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

Aqui estão as aulas. Observe que você também pode usar a Csv.Escapefunção para gravar CSV válido.

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
Você também pode precisar traduzir \ r \ n para conformidade com o Windows, dependendo do seu aplicativo.
Mandrake

3
@NadaNaeem, gostaria de elaborar?
harpo 07/07

ele não está contando os itens em uma linha arquivo CSV corretamente, ele não está lidando bem com as vírgulas nos campos e coragem retornos e torneiras
Nada N. Hantouli

-1 OP não especifica um idioma que está criando o arquivo. Se qualquer outro programador vier aqui procurando uma solução em qualquer idioma, exceto C #, ele não encontrará uma solução que possa ser usada nesta resposta.
Ben Leggiero

8
@ BenC.R.Leggiero, então suponho que você também deva votar a questão, pois ela não pode ser respondida pelo seu padrão. Como é, o código equivale a uma implementação formal de uma especificação simples e pode ser facilmente traduzido para qualquer idioma comumente usado.
Harpo

395

Para 2017, o csv está totalmente especificado - RFC 4180.

É uma especificação muito comum e é completamente coberta por muitas bibliotecas ( exemplo ).

Basta usar qualquer biblioteca csv facilmente disponível - ou seja, RFC 4180.


Na verdade, há uma especificação para o formato CSV e como lidar com vírgulas:

Os campos contendo quebras de linha (CRLF), aspas duplas e vírgulas devem ser colocados entre aspas duplas.

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

Então, para ter valores fooe bar,baz, faça o seguinte:

foo,"bar,baz"

Outro requisito importante a ser considerado (também das especificações):

Se aspas duplas forem usadas para delimitar campos, uma aspas dupla aparecendo dentro de um campo deve ser escapada precedendo-a com outra aspas dupla. Por exemplo:

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

120
"Os campos que contêm quebras de linha (CRLF), aspas duplas e vírgulas devem ser colocados entre aspas duplas."
Eli

42
"Se aspas duplas forem usadas para delimitar campos, uma aspas dupla aparecendo dentro de um campo deve ser escapada precedendo-a com outra aspas dupla."
C. Dragão 76

11
Não é realmente uma especificação, mas provavelmente ainda é útil. Ele diz ... "Não existe especificação formal, o que permite uma grande variedade de interpretações de arquivos CSV. Esta seção documenta o formato que parece ser seguido pela maioria das implementações".
23611 Justin Clarke

5
Além disso, não esqueça que, apesar do nome, os valores de CSV na linha podem ser separados não apenas por vírgulas - pelo menos nas plataformas Windows. Ela depende das configurações regionais atuais (intl.cpl na linha de comando, "Configurações avançadas"), em particular, separador de lista: System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.
Lx 26/08/13

4
Coloque as informações relevantes nesta resposta, além do link, para A) Remova a maioria dos comentários acima (e os meus), B) Economize muito mais pessoas do que o respondente o tempo para ir para outra página e encontrar as informações relevantes. dados, C) Impedir Rot Rotação.
User66001

76

O formato CSV usa vírgulas para separar valores, valores que contêm retornos de carro, alimentações de linha, vírgulas ou aspas duplas são cercados por aspas duplas. Os valores que contêm aspas duplas são citados e cada citação literal é escapada por uma citação imediatamente anterior: por exemplo, os 3 valores:

test
list, of, items
"go" he said

seria codificado como:

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

Qualquer campo pode ser citado, mas apenas os que contêm vírgulas, CR / NL ou aspas devem ser citados.

Não existe um padrão real para o formato CSV, mas quase todos os aplicativos seguem as convenções documentadas aqui . A RFC mencionada em outro lugar não é um padrão para CSV, é uma RFC para usar CSV no MIME e contém algumas limitações não convencionais e desnecessárias que o tornam inútil fora do MIME.

Um problema que muitos módulos CSV que eu vi não acomodam é o fato de que várias linhas podem ser codificadas em um único campo, o que significa que você não pode assumir que cada linha é um registro separado, ou você não deve permitir novas linhas no seu dados ou esteja preparado para lidar com isso.


40

Coloque aspas duplas em torno de strings. Isso geralmente é o que o Excel faz .

Ala Eli,

você evita aspas duplas como duas aspas duplas. Por exemplo, "test1", "foo" "bar", "test2"


basicamente, o mesmo conceito que a Identificadores citados
Bob A guarda de

1
você evita aspas duplas como duas aspas duplas. Por exemplo, "test1", "foo" "bar", "test2"
Eli

Basta colocar aspas em torno da corda não funciona quando um "é imediatamente seguido por uma vírgula
MondKin

9

Você pode colocar aspas duplas nos campos. Não gosto dessa abordagem, pois acrescenta outro caractere especial (aspas duplas). Basta definir um caractere de escape (geralmente barra invertida) e usá-lo sempre que precisar escapar de algo:

dados, mais dados, mais dados \, até mais

Você não precisa tentar corresponder aspas e possui menos exceções para analisar. Isso simplifica seu código também.


3
Rápido e sujo, mas não funciona se você realmente tem uma entrada que contém "\",
Sarp Kaya

1
Sarp, é por isso que um \\ duplo é uma barra invertida, já que agora se torna outro caractere especial.
Grungondola

1
Isso funciona, mas não é CSV. É um DSV .
TRiG 25/10/16

8

Existe uma biblioteca disponível através do nuget para lidar com praticamente qualquer CSV bem formado (.net) - CsvHelper

Exemplo para mapear para uma classe:

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

Exemplo para ler campos individuais:

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

Permitir que o cliente conduza o formato do arquivo:
, é o delimitador de campo padrão, "é o valor padrão usado para escapar dos campos que contêm um delimitador, cotação ou final de linha.

Para usar (por exemplo) #para campos e 'para escapar:

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

Mais documentação


3
Seria preferível se você incluísse um exemplo de como usar a CsvHelperbiblioteca para resolver o problema do OP.
George Stocker

Por que quase tudo no .Net tem que ser um "Auxiliar" ... a palavra é quase sem sentido ... como "Gerente".
Bydevev

5

Como mencionado no meu comentário à resposta do harpo, sua solução é boa e funciona na maioria dos casos, no entanto, em alguns cenários, quando as vírgulas são diretamente adjacentes uma à outra, ela não se divide nas vírgulas.

Isso ocorre porque a string Regex se comporta inesperadamente como uma string vertabim. Para que isso se comporte corretamente, todos os caracteres "na sequência de caracteres regex precisam ser escapados manualmente sem usar o escape vertabim.

Ou seja. O regex deve ser este usando escapes manuais:

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

que se traduz em ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"

Ao usar uma sequência vertabim, @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"ele se comporta da seguinte maneira, como você pode ver se você depura o regex:

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

Então, em resumo, eu recomendo a solução do harpo, mas cuidado com essa pequena pegadinha!

Incluímos no CsvReader um pouco de segurança opcional para notificá-lo se esse erro ocorrer (se você tiver um número pré-conhecido de colunas):

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

Isso pode ser injetado através do construtor:

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

Como você lidaria com a linha do cabeçalho? Eu estou tentando mapear o CSV para C # objetos que são todos os tipos, mas as quebras de linha de cabeçalho porque seus todas as cordas ...
TCOE

Não é [^""]o mesmo que [^"]? A duplicação de um caractere dentro de uma especificação de classe de caractere é redundante, certo?
Minh Tran

4

Adicione uma referência ao Microsoft.VisualBasic (sim, ele diz VisualBasic, mas também funciona em C # - lembre-se de que, no final, tudo é apenas IL).

Use a Microsoft.VisualBasic.FileIO.TextFieldParserclasse para analisar o arquivo CSV Aqui está o código de exemplo:

 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 

Sim, esta é uma classe muito útil em um espaço para nome um tanto infeliz ;-). Para resolver a questão original, no entanto, você também deve definir parser.HasFieldsEnclosedInQuotes = true;e o arquivo de entrada precisará incluir campos que contenham vírgulas entre aspas conforme a especificação do CSV - o Excel já faz isso.
Christopher King


4

Caso você esteja em um sistema * nix , tenha acesso sede possa haver uma ou mais vírgulas indesejadas apenas em um campo específico do seu CSV, use a seguinte linha para incluí-las "como RFC4180. 2 propõe:

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

Dependendo de qual campo a (s) vírgula (s) indesejada (s) pode estar, você deve alterar / estender os grupos de captura da expressão regular (e a substituição).
O exemplo acima incluirá o quarto campo (de seis) entre aspas.

insira a descrição da imagem aqui

Em combinação com a --in-placeopção- você pode aplicar essas alterações diretamente no arquivo.

Para "construir" a regex correta, existe um princípio simples a seguir:

  1. Para cada campo no seu CSV que vem antes do campo com as vírgulas indesejadas, você escreve um [^,]*,e junta todos eles em um grupo de captura.
  2. Para o campo que contém as vírgulas indesejadas que você escreve (.*).
  3. Para cada campo após o campo com vírgulas indesejadas, você escreve um ,.* e junta todos eles em um grupo de captura.

Aqui está uma breve visão geral das diferentes regexes / substituições possíveis, dependendo do campo específico. Se não for dado, a substituição é \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 você deseja remover as vírgulas indesejadas, em sedvez de colocá-las entre aspas, consulte esta resposta .


3

Se você deseja reinventar a roda, o seguinte pode funcionar para você:

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

Na Europa, temos esse problema antes que esta questão. Na Europa, usamos todas as vírgulas para um ponto decimal. Veja estes números abaixo:

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

Portanto, não é possível usar o separador de vírgulas para arquivos CSV. Por esse motivo, os arquivos CSV na Europa são separados por ponto e vírgula ( ;) .

Programas como o Microsoft Excel podem ler arquivos com ponto e vírgula e é possível alternar do separador. Você pode até usar uma tab ( \t) como separador. Veja esta resposta do usuário Ceia .


2

Se você estiver interessado em um exercício mais educacional sobre como analisar arquivos em geral (usando o CSV como exemplo), consulte este artigo de Julian Bucknall. Gosto do artigo porque divide as coisas em problemas muito menores e muito menos intransponíveis. Você primeiro cria uma gramática e, depois de ter uma boa gramática, é um processo relativamente fácil e metódico converter a gramática em código.

O artigo usa C # e tem um link na parte inferior para baixar o código.


1

Aqui está uma pequena solução:

Você pode usar um sinal numérico inferior grego (U + 0375)

Parece assim ͵

O uso desse método poupa muitos recursos também ...


1

Basta usar o SoftCircuits.CsvParser no NuGet. Ele lida com todos esses detalhes e lida com eficiência com arquivos muito grandes. E, se necessário, ele pode até importar / exportar objetos mapeando colunas para as propriedades do objeto. Além disso, meus testes mostraram que a média é quase 4 vezes mais rápida que o popular CsvHelper.


0

Como se trata de práticas gerais, vamos começar pelas regras básicas:

  1. Não use CSV, use XML com uma biblioteca para ler e gravar o arquivo xml.

  2. Se você deve usar o CSV. Faça-o corretamente e use uma biblioteca gratuita para analisar e armazenar os arquivos CSV.

Para justificar 1), a maioria dos analisadores CSV não tem conhecimento de codificação; portanto, se você não está lidando com US-ASCII, está solicitando problemas. Por exemplo, o Excel 2002 está armazenando o CSV na codificação local sem nenhuma observação sobre a codificação. O padrão CSV não é amplamente adotado :(. Por outro lado, o padrão xml é bem adotado e lida com codificações muito bem.

Para justificar 2), existem muitos analisadores csv em quase todo o idioma, portanto, não há necessidade de reinventar a roda, mesmo que as soluções pareçam bastante simples.

Para citar alguns:

  • para python use build no módulo csv

  • para perl, verifique CPAN e Text :: CSV

  • para php use build em funções fgetcsv / fputcsv

  • para biblioteca Java SuperCVS

Realmente, não há necessidade de implementar isso manualmente, se você não for analisá-lo no dispositivo incorporado.


12
XML nem sempre é a resposta. CSV é o formato certo para o trabalho quando você tem muitos dados tabulares densos (por exemplo, uma planilha). Essas tags apresentam muita sobrecarga e, se todas as linhas tiverem um formato idêntico, não haverá necessidade de ser explícito sobre o que cada valor representa. XML é ótimo quando você possui dados hierárquicos complicados ou registros com campos opcionais. Nem sempre é esse o caso.
23611 Adam Jaskiewicz

Em teoria, as "tags" introduzem um pouco de sobrecarga, mas não consigo pensar em nenhum aplicativo da vida real onde ele comece a ser um problema. Você tem exemplos práticos? Para trabalhar com dados, deve-se usar um banco de dados em vez de csv. se falarmos sobre serialização de dados (backups, troca de dados), será importante se a análise demorar uma semana em vez de cinco dias?
Piotr Czapla 20/04/09

2
Basicamente, qualquer situação em que você tenha dados que sejam melhor representados por uma tabela. Digamos que você tenha dados de uma dúzia de sensores diferentes que você faz uma amostragem de vez em quando e registra o carimbo de data e hora e o valor de cada um dos sensores naquele momento. Cada registro é idêntico: registro de data e hora, sensor0, sensor1, ... sensor11. O XML é ótimo para representar dados complexos e irregulares, mas é um formato bastante pesado que não se encaixa em todas as situações. KISS
Adam Jaskiewicz

10
Algumas pessoas veem um problema e dizem "eu sei, vou usar XML!" Agora eles tem dois problemas.
23611 Adam Jaskiewicz

Concordo plenamente que o xml não é uma resposta para tudo. Especialmente, não é adequado como substituto de banco de dados nem para arquivos de configuração. Mas aqui a questão era sobre o intercâmbio de dados para o qual o XML foi projetado.
Piotr Czapla 21/04/09

0

Você pode ler o arquivo csv assim.

isso faz uso de divisões e cuida dos espaços.

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

Primeiro, vamos nos perguntar: "Por que sentimos a necessidade de manipular vírgulas de maneira diferente para arquivos CSV?"

Para mim, a resposta é: "Quando eu exporto dados para um arquivo CSV, as vírgulas em um campo desaparecem e meu campo é separado em vários campos, onde as vírgulas aparecem nos dados originais". (Isso porque a vírgula é o caractere separador de campo CSV.)

Dependendo da sua situação, pontos e vírgulas também podem ser usados ​​como separadores de campo CSV.

Dado os meus requisitos, posso usar um caractere, por exemplo, aspas simples de 9, que se parece com uma vírgula.

Então, veja como você pode fazê-lo no 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
}

O segundo caractere de vírgula na função Substituir é decimal 8218.

Esteja ciente de que, se você tiver clientes que podem ter leitores de texto apenas ascii, esse caractere dizimado 8218 não parecerá uma vírgula. Se esse for o seu caso, recomendo colocar o campo com uma vírgula (ou ponto-e-vírgula) com aspas duplas conforme a RFC 4128: https://tools.ietf.org/html/rfc4180


0

Geralmente codifico por URL os campos que podem ter vírgulas ou caracteres especiais. E então decodifique quando estiver sendo usado / exibido em qualquer meio visual.

(vírgulas se tornam% 2C)

Todo idioma deve ter métodos para codificar e decodificar URLs.

por exemplo, em java

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

Eu sei que esta é uma solução muito geral e pode não ser ideal para situações em que o usuário deseja visualizar o conteúdo do arquivo csv manualmente.


0

Normalmente, faço isso nos meus arquivos CSV, analisando as rotinas. Suponha que a variável 'linha' seja uma linha dentro de um arquivo CSV e os valores de todas as colunas estejam entre aspas duplas. Após a execução das duas linhas abaixo, você obterá colunas CSV na coleção 'values'.

// 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
Por que meu código nunca é exibido em várias cores no StackOverflow? Recuo por quatro espaços.
user1451111


0

A solução mais simples que encontrei é a que o LibreOffice usa:

  1. Substitua todos os literais "por
  2. Coloque aspas duplas em torno de sua string

Você também pode usar aquele que o Excel usa:

  1. Substitua todos os literais "por""
  2. Coloque aspas duplas em torno de sua string

Observe que outras pessoas recomendaram executar apenas a etapa 2 acima, mas isso não funciona com as linhas em que a "é seguido por a ,, como em um CSV em que você deseja ter uma única coluna com a string hello",world, como leria o CSV:

"hello",world"

Que é interpretado como uma linha com duas colunas: helloeworld"


1
Por regras padrão, qualquer campo que contenha o caractere de divisão ou a citação é cercado por aspas e todas as aspas que são duplicadas, portanto, não há problema. Seu hello",worldcampo simplesmente precisaria ser salvo como "hello"",world", que pode ser analisado 100% corretamente.
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

Eu usei a biblioteca Csvreader, mas usando isso, obtive dados explodindo a partir da vírgula (,) no valor da coluna.

Portanto, se você deseja inserir dados do arquivo CSV que contenham vírgula (,) na maioria dos valores das colunas, use a função abaixo. Autor link => 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

Usei a biblioteca papaParse para analisar o arquivo CSV e ter os pares de valores-chave (chave / cabeçalho / primeira linha do valor do arquivo CSV).

Aqui está um exemplo que eu uso:

https://codesandbox.io/embed/llqmrp96pm

ele possui o arquivo dummy.csv para ter a demonstração de análise de CSV.

Eu o usei no reactJS, embora seja fácil e simples replicar no aplicativo escrito em qualquer idioma.


0

Um exemplo pode ajudar a mostrar como as vírgulas podem ser exibidas em um arquivo .csv. Crie um arquivo de texto simples da seguinte maneira:

Salve este arquivo de texto como um arquivo de texto com o sufixo ".csv" e abra-o com o Excel 2000 no Windows 10.

aa, bb, cc, d; d "Na apresentação da planilha, a linha abaixo deve se parecer com a linha acima, exceto que a abaixo mostra uma vírgula exibida em vez de um ponto e vírgula entre os ds." aa, bb, cc, "d, d", isso funciona mesmo no Excel

aa, bb, cc, "d, d", funciona mesmo no Excel 2000 aa, bb, cc, "d, d", funciona mesmo no Excel 2000 aa, bb, cc, "d, d", funciona mesmo no Excel 2000

aa, bb, cc, "d, d", Isso falha no Excel 2000 devido ao espaço antes da 1ª cotação aa, bb, cc, "d, d", isso falha no Excel 2000 devido ao espaço antes da 1ª cotação aa, bb, cc, "d, d", isso falha no Excel 2000 devido ao espaço existente na primeira cotação

aa, bb, cc, "d, d", Isso funciona mesmo no Excel 2000, mesmo com espaços antes e depois da segunda cotação. aa, bb, cc, "d, d", Isso funciona mesmo no Excel 2000, mesmo com espaços antes e depois da segunda cotação. aa, bb, cc, "d, d", Isso funciona mesmo no Excel 2000, mesmo com espaços antes e depois da segunda cotação.

Regra: Se você deseja exibir uma vírgula em uma célula (campo) de um arquivo .csv: "Inicie e termine o campo com aspas duplas, mas evite o espaço em branco antes da primeira cotação"


-1

Acho que a solução mais fácil para esse problema é ter o cliente para abrir o csv no excel e, em seguida, pressionar a tecla Ctrl + r para substituir toda a vírgula pelo identificador desejado. Isso é muito fácil para o cliente e requer apenas uma alteração no seu código para ler o delimitador de sua escolha.


Quem disse que eles têm o Excel? Na verdade quem diz que seu mesmo um ser humano que está fazendo o upload ...?
bytedev

-3

Use um caractere de tabulação (\ t) para separar os campos.


4
-1 Ótimo até que alguém use uma guia em seu valor, então você volta ao problema que a pessoa que está fazendo a pergunta tem. Trocar um char delimitador por outro não resolverá o problema.
Bydevev

Absurdo. As pessoas não podem inserir guias na entrada de dados. Na maioria dos formulários, isso simplesmente move o ponto de entrada de dados para o próximo campo.
Pierre

6
"As pessoas não podem inserir guias nas entradas de dados" .... você está falando sério? A) é claro que uma pessoa pode colocar uma guia em um campo de entrada B) quem diz que é uma GUI da qual os dados vêm? C) quem disse que é um humano que está inserindo os dados?
Bydevev
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.