Manejo de comas en un archivo CSV

472

Estoy buscando sugerencias sobre cómo manejar un archivo csv que se está creando, luego cargado por nuestros clientes, y que puede tener una coma en un valor, como el nombre de una empresa.

Algunas de las ideas que estamos viendo son: identificadores citados (valor "," valores "," etc.) o usando un | en lugar de una coma. El mayor problema es que tenemos que facilitarlo, o el cliente no lo hará.

Bob el conserje
fuente
el cliente lo escribe y lo carga
Bob The Janitor el
1
Aquí está la solución para administrar commos internos en el archivo csv. visite stackoverflow.com/questions/9889225/…
Hasan Abrar
en iOS, esencialmente debes usar github.com/Flinesoft/CSVImporter
Fattie
3
Tenga en cuenta que este control de calidad es antiguo. Hoy en día csv significa RFC 4180 y eso es todo.
Fattie
Tengo exactamente el mismo problema, tratando de totalizar una columna en un archivo csv que está separado por comas. No hay problema con un comando awk. Lamentablemente, algunas celdas pueden contener comas (en una dirección, por ejemplo), otras celdas no. Buscando una solución compatible con Linux pero no estoy seguro de por dónde empezar.
greenage

Respuestas:

223

Como han dicho otros, debe escapar de los valores que incluyen comillas. Aquí hay un pequeño lector CSV en C♯ que admite valores entre comillas, incluidas las comillas incrustadas y los retornos de carro.

Por cierto, este es un código probado por unidad. Lo estoy publicando ahora porque esta pregunta parece surgir mucho y es posible que otros no quieran una biblioteca completa cuando lo hará un simple soporte de CSV.

Puede usarlo de la siguiente manera:

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

Aquí están las clases. Tenga en cuenta que también puede usar la Csv.Escapefunción para escribir 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' };
}
harpo
fuente
2
Es posible que también necesite traducir \ r \ n para el cumplimiento de Windows, dependiendo de su aplicación.
Mandrake
3
@NadaNaeem, ¿quieres elaborar?
harpo
no está contando los elementos en una fila de archivos csv correctamente, no se trata bien con las comas en los campos y el coraje regresa y toca
Nada N. Hantouli
-1 OP no especifica un idioma que está creando el archivo. Si algún otro programador viene aquí buscando una solución en cualquier lenguaje que no sea C #, no encontrará una solución que pueda usar en esta respuesta.
Ben Leggiero
8
@ BenC.R.Leggiero, entonces supongo que también debe rechazar la pregunta, ya que no tiene respuesta para su estándar. Tal como están las cosas, el código equivale a una implementación formal de una especificación simple, y puede traducirse fácilmente a cualquier lenguaje de uso común.
harpo
395

Para 2017, csv está completamente especificado: RFC 4180.

Es una especificación muy común, y está completamente cubierta por muchas bibliotecas ( ejemplo ).

Simplemente use cualquier biblioteca csv fácilmente disponible , es decir RFC 4180.


En realidad, hay una especificación para el formato CSV y cómo manejar las comas:

Los campos que contienen saltos de línea (CRLF), comillas dobles y comas deben ir entre comillas dobles.

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

Entonces, para tener valores fooy bar,bazhacer esto:

foo,"bar,baz"

Otro requisito importante a tener en cuenta (también de la especificación):

Si se utilizan comillas dobles para encerrar los campos, se debe escapar una comilla doble que aparezca dentro de un campo precediéndola con otra comilla doble. Por ejemplo:

"aaa","b""bb","ccc"
Corey Trager
fuente
120
"Los campos que contienen saltos de línea (CRLF), comillas dobles y comas deben ir entre comillas dobles".
Eli el
42
"Si se utilizan comillas dobles para encerrar los campos, se debe escapar una comilla doble que aparezca dentro de un campo precediéndola con otra comilla doble".
C.Dragon 76
11
No es realmente una especificación, pero probablemente sea útil. Dice ... "No existe una especificación formal que permita una amplia variedad de interpretaciones de los archivos CSV. Esta sección documenta el formato que parece ser seguido por la mayoría de las implementaciones".
Justin Clarke
55
Además, no olvide que, a pesar de su nombre, los valores CSV en la fila pueden estar separados no solo por comas, al menos en las plataformas Windows. Depende de la configuración regional actual (intl.cpl en línea de comandos, "Configuración avanzada"), en particular, separador de lista: System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.
lxa
44
Ponga información relevante en esta respuesta, además del enlace, en A) Elimine la mayoría de los comentarios anteriores (y los míos), B) Ahorre a tantas personas más que el que responde el tiempo para ir a otra página y encontrar la información relevante datos, C) Evitar la pudrición del enlace.
user66001
76

El formato CSV usa comas para separar valores, los valores que contienen retornos de carro, avances de línea, comas o comillas dobles están rodeados por comillas dobles. Los valores que contienen comillas dobles se citan y cada cita literal se escapa mediante una cita inmediatamente anterior: por ejemplo, los 3 valores:

test
list, of, items
"go" he said

se codificaría como:

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

Cualquier campo puede ser citado, pero sólo los campos que contienen comas, CR / NL, o las citas debe ser citado.

No existe un estándar real para el formato CSV, pero casi todas las aplicaciones siguen las convenciones documentadas aquí . El RFC que se mencionó en otra parte no es un estándar para CSV, es un RFC para usar CSV dentro de MIME y contiene algunas limitaciones no convencionales e innecesarias que lo hacen inútil fuera de MIME.

Un problema que muchos módulos CSV que he visto no tienen en cuenta es el hecho de que se pueden codificar varias líneas en un solo campo, lo que significa que no puede suponer que cada línea es un registro separado, tampoco debe permitir nuevas líneas en su datos o estar preparado para manejar esto.

Robert Gamble
fuente
40

Pon comillas dobles alrededor de las cadenas. Eso es generalmente lo que hace Excel .

Ala Eli

te escapas de una comilla doble como dos comillas dobles. Por ejemplo, "test1", "foo", "bar", "test2"

Joe Phillips
fuente
básicamente el mismo concepto que un identificador citado
Bob The Janitor el
1
te escapas de una comilla doble como dos comillas dobles. Por ejemplo, "test1", "foo" "barra", "test2"
Eli
Simplemente poner comillas dobles alrededor de la cadena no funciona cuando un "es seguido inmediatamente por una coma
MondKin
9

Puede poner comillas dobles alrededor de los campos. No me gusta este enfoque, ya que agrega otro carácter especial (la comilla doble). Simplemente defina un carácter de escape (generalmente barra invertida) y úselo donde necesite escapar de algo:

datos, más datos, más datos \, incluso, aún más

No tiene que intentar hacer coincidir las comillas, y tiene menos excepciones para analizar. Esto también simplifica su código.

Adam Jaskiewicz
fuente
3
Rápido y sucio, pero no funciona si realmente tiene una entrada que contiene "\,"
Sarp Kaya
1
Sarp, es por eso que un doble \\ es una barra invertida escapada, ya que ahora se convierte en otro personaje especial.
Grungondola
1
Esto funciona, pero no es CSV. Es un DSV .
TRiG
8

Hay una biblioteca disponible a través de nuget para tratar prácticamente cualquier CSV (.net) bien formado - CsvHelper

Ejemplo para asignar a una clase:

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

Ejemplo para leer campos individuales:

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

Dejar que el cliente maneje el formato de archivo:
, es el delimitador de campo estándar, "es el valor estándar utilizado para escapar de los campos que contienen un delimitador, una comilla o un final de línea.

Para usar (por ejemplo) #para campos y 'para escapar:

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

Más documentación

NikolaiDante
fuente
3
Sería preferible si incluyera un ejemplo de cómo usar la CsvHelperbiblioteca para resolver el problema del OP.
George Stocker
¿Por qué casi todo en .Net tiene que ser un "Ayudante" ... la palabra casi no tiene sentido ... como "Gerente".
bytedev
5

Como mencioné en mi comentario a la respuesta de Harpo, su solución es buena y funciona en la mayoría de los casos, sin embargo, en algunos escenarios cuando las comas están directamente adyacentes entre sí, no se divide en las comas.

Esto se debe a que la cadena Regex se comporta inesperadamente como una cadena vertabim. Para que este comportamiento sea correcto, todos los "caracteres en la cadena de expresiones regulares deben ser escapados manualmente sin usar el escape vertabim.

Es decir. La expresión regular debería ser esto usando escapes manuales:

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

que se traduce en ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"

Cuando se utiliza una cadena vertabim, @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"se comporta de la siguiente manera, como puede ver si depura la expresión regular:

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

En resumen, recomiendo la solución de harpo, ¡pero ten cuidado con este pequeño problema!

He incluido en CsvReader una pequeña opción a prueba de fallos para notificarle si se produce este error (si tiene un número de columnas previamente conocido):

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

Esto se puede inyectar a través del constructor:

public CsvReader(string fileName, int expectedDataLength = 0) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
    _expectedDataLength = expectedDataLength;
}
MikeDub
fuente
¿Cómo harías para manejar la fila del encabezado? Estoy tratando de mapear el csv a C # objetos que se encuentran todos los tipos, pero la fila de encabezado se rompe porque sus todas las cadenas ...
TCOE
¿No es lo [^""]mismo que [^"]? La duplicación de un carácter dentro de una especificación de clase de caracteres es redundante, ¿verdad?
Minh Tran
4

Agregue una referencia a Microsoft.VisualBasic (sí, dice VisualBasic pero también funciona en C #, recuerde que al final todo es IL).

Use la Microsoft.VisualBasic.FileIO.TextFieldParserclase para analizar el archivo CSV. Aquí está el código de muestra:

 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 
mvilaskumar
fuente
Sí, esta es una clase muy útil en un espacio de nombres algo desafortunado ;-). Sin embargo, para abordar la pregunta original, también debe configurar parser.HasFieldsEnclosedInQuotes = true;y el archivo de entrada debería encerrar los campos que contienen comas entre comillas según la especificación CSV: Excel ya lo hace.
Christopher King
4

En caso de que esté en un sistema * nix , tenga acceso sedy pueda haber una o más comas no deseadas solo en un campo específico de su CSV, puede usar la siguiente línea para encerrarlas "como Sección RFC4180 2 propone:

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

Dependiendo del campo en el que se encuentren las comas no deseadas, deberá modificar / ampliar los grupos de captura de la expresión regular (y la sustitución).
El ejemplo anterior incluirá el cuarto campo (de seis) entre comillas.

ingrese la descripción de la imagen aquí

En combinación con la --in-placeopción aplicar estos cambios directamente al archivo.

Para "construir" la expresión regular correcta, hay un principio simple a seguir:

  1. Para cada campo en su CSV que viene antes del campo con la (s) coma (s) no deseada, usted escribe uno [^,]*,y los pone todos juntos en un grupo de captura.
  2. Para el campo que contiene las comas no deseadas que escribe (.*).
  3. Para cada campo después del campo con la (s) coma (s) no deseada, usted escribe una ,.* y las pone todas juntas en un grupo de captura.

Aquí hay una breve descripción de las diferentes expresiones regulares / sustituciones dependiendo del campo específico. Si no se da, la sustitución es \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)

Si desea eliminar las comas no deseadas en sedlugar de encerrarlas entre comillas, consulte esta respuesta .

Basti M
fuente
3

Si tiene ganas de reinventar la rueda, lo siguiente puede funcionar para usted:

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

En Europa tenemos este problema antes que esta pregunta. En Europa usamos toda una coma para un punto decimal. Vea estos números a continuación:

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

Por lo tanto, no es posible usar el separador de coma para los archivos CSV. Por esa razón, los archivos CSV en Europa están separados por un punto y coma ( ;) .

Programas como Microsoft Excel pueden leer archivos con un punto y coma y es posible cambiar de separador. Incluso podría usar una pestaña ( \t) como separador. Vea esta respuesta del usuario de Supper .

H. Pauwelyn
fuente
2

Si está interesado en un ejercicio más educativo sobre cómo analizar archivos en general (usando CSV como ejemplo), puede consultar este artículo de Julian Bucknall. Me gusta el artículo porque divide las cosas en problemas mucho más pequeños que son mucho menos insuperables. Primero crea una gramática, y una vez que tiene una buena gramática, es un proceso relativamente fácil y metódico para convertir la gramática en código.

El artículo usa C # y tiene un enlace en la parte inferior para descargar el código.

Phil
fuente
1

Aquí hay una pequeña solución ordenada:

En su lugar, puede usar un signo de número inferior griego (U + 0375)

Se ve así ͵

El uso de este método también le ahorra muchos recursos ...

Konstantine Nikka-Sher Piterma
fuente
1

Simplemente use SoftCircuits.CsvParser en NuGet. Manejará todos esos detalles por usted y manejará eficientemente archivos muy grandes. Y, si es necesario, incluso puede importar / exportar objetos asignando columnas a las propiedades del objeto. Además, mis pruebas mostraron que promedia casi 4 veces más rápido que el popular CsvHelper.

Jonathan Wood
fuente
0

Como se trata de prácticas generales, comencemos por las reglas generales:

  1. No use CSV, use XML con una biblioteca para leer y escribir el archivo xml.

  2. Si debe usar CSV. Hágalo correctamente y use una biblioteca gratuita para analizar y almacenar los archivos CSV.

Para justificar 1), la mayoría de los analizadores CSV no son conscientes de la codificación, por lo que si no está tratando con US-ASCII, está solicitando problemas. Por ejemplo, Excel 2002 está almacenando el CSV en codificación local sin ninguna nota sobre la codificación. El estándar CSV no es ampliamente adoptado :(. Por otro lado, el estándar xml está bien adoptado y maneja las codificaciones bastante bien.

Para justificar 2), hay toneladas de analizadores csv para casi todo el lenguaje, por lo que no hay necesidad de reinventar la rueda, incluso si las soluciones parecen bastante simples.

Por nombrar algunos:

  • para python use build en el módulo csv

  • para perl verifique CPAN y Texto :: CSV

  • para php use construir en funciones fgetcsv / fputcsv

  • para java verifique la biblioteca SuperCVS

Realmente no hay necesidad de implementar esto a mano si no vas a analizarlo en un dispositivo incorporado.

Piotr Czapla
fuente
12
XML no siempre es la respuesta. CSV es el formato correcto para el trabajo cuando tiene muchos datos tabulares densos (es decir, una hoja de cálculo). Esas etiquetas introducen una gran cantidad de gastos generales, y si todas y cada una de las líneas tienen un formato idéntico, no es necesario ser explícito sobre lo que representa cada valor. XML es excelente cuando tiene datos jerárquicos complicados o registros con campos opcionales. Ese no es siempre el caso.
Adam Jaskiewicz el
En teoría, las "etiquetas" introducen un poco de sobrecarga, pero no puedo pensar en ninguna aplicación de la vida real donde empiece a ser un problema. ¿Tienes algún ejemplo práctico? Para trabajar en datos, se debe usar una base de datos en lugar de csv. Si hablamos de serialización de datos (copias de seguridad, intercambio de datos), ¿importará si el análisis lleva una semana en lugar de 5 días?
Piotr Czapla
2
Básicamente, cualquier situación en la que tenga datos mejor representados por una tabla. Supongamos que tiene datos de una docena de sensores diferentes que muestrea cada cierto tiempo, y registra la marca de tiempo y el valor de cada uno de los sensores en ese momento. Cada registro es idéntico: marca de tiempo, sensor0, sensor1, ... sensor11. XML es excelente para representar datos complejos e irregulares, pero es un formato bastante pesado que no se adapta a todas las situaciones. KISS
Adam Jaskiewicz
10
Algunas personas ven un problema y dicen "¡Lo sé, usaré XML!" Ahora ellos tienen dos problemas.
Adam Jaskiewicz
Estoy totalmente de acuerdo en que xml no es una respuesta para todo. Especialmente no es adecuado como reemplazo de base de datos ni para archivos de configuración. Pero aquí la pregunta era sobre el intercambio de datos para el cual XML fue diseñado.
Piotr Czapla
0

Puede leer el archivo csv de esta manera.

Esto hace uso de divisiones y cuida los espacios.

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++;
         }
Eric
fuente
0

Primero, preguntémonos: "¿Por qué sentimos la necesidad de manejar las comas de manera diferente para los archivos CSV?"

Para mí, la respuesta es: "Porque cuando exporto datos a un archivo CSV, las comas en un campo desaparecen y mi campo se separa en múltiples campos donde las comas aparecen en los datos originales". (Eso es porque la coma es el carácter separador de campo CSV).

Dependiendo de su situación, los punto y coma también se pueden usar como separadores de campo CSV.

Dados mis requisitos, puedo usar un carácter, por ejemplo, una comilla simple de bajo 9, que se parece a una coma.

Entonces, así es como puedes hacerlo en 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
}

El segundo carácter con aspecto de coma en la función Reemplazar es el decimal 8218.

Tenga en cuenta que si tiene clientes que pueden tener lectores de texto de solo ascii, este carácter de décima 8218 no se verá como una coma. Si este es su caso, entonces recomendaría rodear el campo con la coma (o punto y coma) con comillas dobles según RFC 4128: https://tools.ietf.org/html/rfc4180

l3x
fuente
0

En general, codifico con URL los campos que pueden tener comas o caracteres especiales. Y luego descifrarlo cuando se está utilizando / muestra en cualquier medio visual.

(las comas se convierten en% 2C)

Cada idioma debe tener métodos para codificar URL y decodificar cadenas.

por ejemplo, en Java

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

Sé que esta es una solución muy general y podría no ser ideal para situaciones en las que el usuario quiere ver el contenido del archivo csv, manualmente.

hariszhr
fuente
0

Por lo general, hago esto en mis rutinas de análisis de archivos CSV. Suponga que la variable 'línea' es una línea dentro de un archivo CSV y todos los valores de las columnas están encerrados entre comillas dobles. Después de que se ejecuten las dos líneas siguientes, obtendrá columnas CSV en la colección 'valores'.

// 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();
usuario1451111
fuente
1
¿Por qué mi código nunca se muestra en varios colores en StackOverflow? Sangría por cuatro espacios.
user1451111
0

La solución más simple que he encontrado es la que usa LibreOffice:

  1. Reemplazar todo literal "por
  2. Pon comillas dobles alrededor de tu cadena

También puede usar el que usa Excel:

  1. Reemplazar todo literal "por""
  2. Pon comillas dobles alrededor de tu cadena

Observe que otras personas recomendaron hacer solo el paso 2 anterior, pero eso no funciona con líneas donde a "está seguido de a ,, como en un CSV donde desea tener una sola columna con la cadena hello",world, ya que el CSV leería:

"hello",world"

Que se interpreta como una fila con dos columnas: helloyworld"

MondKin
fuente
1
Según las reglas estándar, cualquier campo que contenga el carácter dividido o la cita está rodeado de comillas, y las comillas dentro de ellas se duplican, por lo que no hay problema. Su hello",worldcampo simplemente debería guardarse como "hello"",world", que se puede analizar 100% correctamente.
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;
        }
    }
Rajat26
fuente
0

Utilicé la biblioteca Csvreader pero al usarla obtuve datos al explotar desde la coma (,) en el valor de la columna.

Entonces, si desea insertar datos de archivo CSV que contengan una coma (,) en la mayoría de los valores de las columnas, puede usar la siguiente función. Enlace del autor => 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;
}
Vir
fuente
0

Usé la biblioteca papaParse para analizar el archivo CSV y tener los pares clave-valor (clave / encabezado / primera fila del archivo CSV-valor).

Aquí hay un ejemplo que uso:

https://codesandbox.io/embed/llqmrp96pm

tiene un archivo dummy.csv para tener la demostración de análisis CSV.

Lo he usado en reactJS, aunque es fácil y sencillo de replicar en una aplicación escrita en cualquier idioma.

parag patel
fuente
0

Un ejemplo podría ayudar a mostrar cómo se pueden mostrar comas en un archivo .csv. Cree un archivo de texto simple de la siguiente manera:

Guarde este archivo de texto como un archivo de texto con el sufijo ".csv" y ábralo con Excel 2000 desde Windows 10.

aa, bb, cc, d; d "En la presentación de la hoja de cálculo, la línea de abajo debe verse como la línea de arriba, excepto que la siguiente muestra una coma en lugar de un punto y coma entre las d". aa, bb, cc, "d, d", esto funciona incluso en Excel

aa, bb, cc, "d, d", esto funciona incluso en Excel 2000 aa, bb, cc, "d, d", esto funciona incluso en Excel 2000 aa, bb, cc, "d, d", esto funciona incluso en Excel 2000

aa, bb, cc, "d, d", esto falla en Excel 2000 debido al espacio anterior a la primera cita aa, bb, cc, "d, d", esto falla en Excel 2000 debido al espacio anterior a la primera cita aa, bb, cc, "d, d", esto falla en Excel 2000 debido al espacio debajo de la primera cita

aa, bb, cc, "d, d", esto funciona incluso en Excel 2000 incluso con espacios antes y después de la segunda cita. aa, bb, cc, "d, d", esto funciona incluso en Excel 2000 incluso con espacios antes y después de la segunda cita. aa, bb, cc, "d, d", esto funciona incluso en Excel 2000 incluso con espacios antes y después de la segunda cita.

Regla: si desea mostrar una coma en una celda (campo) de un archivo .csv: "Comience y finalice el campo con comillas dobles, pero evite los espacios en blanco antes de la primera cita"

usuario1247591
fuente
-1

Creo que la solución más fácil para este problema es hacer que el cliente abra el csv en Excel y luego ctrl + r para reemplazar todas las comas con el identificador que desee. Esto es muy fácil para el cliente y requiere solo un cambio en su código para leer el delimitador de su elección.

jamesdeath123
fuente
¿Quién dice que tienen Excel? De hecho, ¿quién dice que incluso un ser humano está haciendo la carga? ...
bytedev
-3

Use un carácter de tabulación (\ t) para separar los campos.

Pierre
fuente
44
-1 Genial hasta que alguien use una pestaña en su valor, luego volverás al problema que tiene la persona que hace la pregunta. Cambiar un delimitador por otro no resolverá el problema.
bytedev
Disparates. Las personas no pueden ingresar pestañas en su entrada de datos. En la mayoría de las formas, eso simplemente mueve el punto de entrada de datos al siguiente campo.
Pierre
66
"La gente no puede ingresar pestañas en su entrada de datos" ... ¿en serio? A) por supuesto, una persona podría poner una pestaña en un campo de entrada B) ¿quién dice que es una GUI de la que provienen los datos? C) ¿quién dice que incluso un humano está ingresando los datos?
bytedev