Colabora
 

Comma-Separated Values - CSV

Funciones para mover información desde y hacia una línea codificada con formato CSV

Fecha: 18/03/2009 (15-03-2009)
Autor: Joaquin Medina Serrano - joaquin@medina.name

 


Introducción

En este artículo se muestra una función para convertir los datos de un “array” en una cadena con formato CSV, y al contrario, dada una cadena CSV, devolver un Array cargado con los datos que contiene la cadena. El análisis de una cadena en formato CSV puede parecer trivial, pero es un autentico infierno de programación. La mejor solución es utilizar Expresiones Regulares. ¡¡Todo un hallazgo!!

 


↑↑↑

Introducción

CSV [Ver CSV] es uno de los primeros formatos de intercambio de datos. Permite volcar en un fichero información, de forma que pueda ser leída por otro ordenador, independientemente del sistema que implemente el receptor

A pesar de que ha sido y es una forma bastante común de mover información entre ordenadores, hasta hace muy poco no ha existido una norma que lo defina. En la actualidad el documento Common Format and MiME Type for Comma-Separated Values (CSV) [Ver RFC-4180] Files del año 2005, es lo más parecido que existe a un estándar sobre este formato aunque sigue sin ser nada oficial


↑↑↑

Descripción del problema

En un trabajo que he estado realizando, se me ha presentado el problema de volcar la información de un DataTable a formato CSV, para mandarlo por internet, y en el destino, recuperar la información del formato CSV y volverlo a colocar en una DataTable.

Aunque en principio, el asunto no representaba ningún problema, me he dedicado a investigar y a buscar algún código que resuelva el problema, y para mi sorpresa, me he encontrado que en realidad no existe, -o por lo menos no lo he encontrado- ninguna solución genérica a este problema, todo son códigos más o menos específicos para mover/recuperar una información pero realizadas específicamente para resolver un problema determinado.

Por esa razón, y como disponía de tiempo, he escrito dos funciones que realizan el trabajo de conversión de un registro de datos a y desde un formato CSV, pero antes de entrar en la descripción del código vamos a ver un poco de información (y/o culturilla)


↑↑↑

Definición del formato

Un documento CSV es un documento Tabular, es decir está formado por líneas y columnas.

Las líneas se separan con un carácter de separación (o terminación) de líneas

Las líneas de todo el documento tienen todas las mismas columnas. Cada línea contiene los datos separados por un separador de campos, en este caso es una coma (,) pero también puede ser cualquier otro carácter, por ejemplo en España es muy normal emplear un punto y coma (;).

Un poco de culturilla: Últimamente se está desarrollando un formato de intercambio de datos [Ver CTX] que es un hijo directo del formato CSV que emplea como carácter separador el carácter pipe ["|", (0x7c)]

Las condiciones que se deben cumplir a la hora de escribir un registro (una línea) codificada según el formato CSV son las siguientes:

Cada registro es una línea del documento, finalizado por el carácter de fin de línea (CRLF)

Por ejemplo:
aaa,bbb,ccc CRLF
zzz,yyy,xxx CRLF

El último registro del fichero, puede tener o no el carácter terminador de fin de línea (CRLF)

Por Ejemplo:
aaa,bbb,ccc CRLF
zzz,yyy,xxx 

El primer registro de todos puede dedicarse a contener los nombres correspondientes de los campos del fichero. No existe ninguna diferencia en cuanto al formato del registro que permita identificar si son datos o son los nombres de los campos. Y además, siguen las mismas reglas de formación que el resto de los datos.

Por Ejemplo
Nombres, apellido_1, apellido_2 CRLF
aaa,bbb,ccc CRLF
zzz,yyy,xxx CRLF

El documento CSV puede contener el número de líneas que deseemos, no existe ninguna limitación.

Cada línea debe contener siempre el mismo número de datos. Si un campo de la línea está vacío se mantiene como vacio

Por ejemplo
Valor inicial -> {nombre} {vacio} {edad}
Valor Final  -> nombre,,edad  (observa las dos comas juntas)

Los espacios se consideran como parte del campo y no deben ser ignorados ni eliminados, sino que tienen que conservarse

Cada campo puede estar o no rodeado de comillas dobles. Si un campo de una línea está rodeado de comillas no obliga al que el campo de la línea siguiente también este rodeado, puede rodearse o no

Por Ejemplo
"aaa","bbb","ccc" CRLF
 zzz ,"yyy",xxx   CRLF

Los campos que contengan en su interior el carácter de fin de línea (CR, LF, o ambos a la vez), y/o el carácter separador de campos -es decir la coma (,)- se rodearan con comillas dobles

Por ejemplo
Valor inicial -> salto de línea CR interno
Valor Final  -> "salto de línea CR interno"
Por Ejemplo
Valor inicial -> 25,96
Valor Final  -> "25,96"

Los campos que contengan en su interior comillas dobles, primero se duplican las comillas y después se rodea todo el campo con comillas dobles

Por ejemplo
Valor inicial -> Ford "Capri"
Primer paso -> Duplicar las comillas --> Ford ""Capri""
Segindo paso - > Rodear el campo con comillas dobles - > --> "Ford ""Capri"""

Aunque no es necesario, creo que es conveniente que aquellos campos que contengan caracteres en blanco, también se rodeen con comillas

Por Ejemplo
Valor inicial -> aquí hay cuatro palabras
Valor Final  -> "aquí hay cuatro palabras"


↑↑↑

El Código.

He desarrollado dos funciones que realizan la conversión de datos desde y hacia CSV, las he llamado "ToLineaCsv" y "LineaCsvToArray",


↑↑↑

La Función "ToLineaCsv"

La Función "ToLineaCsv" recibe una matriz de cadenas (String) con los datos y monta con ellos una línea con formato CSV

Es un poco larga, pero no tiene ningún problema. Consiste en un bucle que recorre los elementos de la matriz, los analiza y decide que tratamiento hay que darles, (rodearlas con comillas, duplicar las comillas interiores, etc.)

 ''' ---------------------------------------------------------------------
 ''' <summary>
 '''    Devuelve una cadena creada a partir de la combinación de 
 '''   varias subcadenas contenidas en una matriz.
 ''' </summary>
 ''' <param name="caracterSeparadorCampos">
 ''' El carácter que se va a utilizar como separador de campos
 ''' </param>
 ''' <param name="matrizElementos">
 ''' La matriz cuyos datos se van a montar como una línea  
 ''' de un documento CSV
 ''' </param>
 ''' <returns>
 ''' Objeto String formado por los elementos de matrizElementos 
 ''' intercalados con la cadena separador. 
 ''' </returns>
 ''' <remarks>
 '''  <para>Por ejemplo, si <paramref name="caracterSeparadorCampos" >
 '''        caracterSeparadorCampos</paramref> es ", " 
 '''        y los elementos de  <paramref name="matrizElementos" >
 '''        matrizElementos</paramref> son 
 '''        "manzana", "naranja", "uva" y "pera", 
 '''        <c>ToLineaCsv(caracterSeparadorCampos, matrizElementos)</c> 
 '''           devuelve una cadena con la siguiente información 
 '''        [manzana, naranja, uva, pera CRLF]. 
 '''  </para>
 '''  <para>Si <paramref name="caracterSeparadorCampos" >
 '''        caracterSeparadorCampos</paramref> es 
 '''        null  (Nothing en Visual Basic), se dispara una 
 '''        excepción [ArgumentNullException]
 ''' </para>
 ''' <para> Cada elemento puede ir rodeado o no de comillas dobles, 
 '''        pero siempre va rodeado si se cumplen cualquiera de las 
 '''        siguientes condiciones:
 ''' </para>
 ''' <para> Existe un carácter separador dentro del elemento 
 '''        P.E. [52.45]  === . ["52.45"]</para>
 ''' <para> Existe un salto de línea dentro del elemento
 '''        (caracteres CrLf)
 ''' </para>
 ''' <para> Existen (uno o más) espacios en blanco en el elemento 
 '''        P.E:[ciudad lineal] === :["ciudad lineal"]</para>
 ''' <para> Existen (una o más) comillas dobles dentro del elemento 
 '''        P.E [pegamento "maravilloso"]. En este caso,  cada una de las 
 '''        comillas dobles existentes se duplican, y a continuación, 
 '''        se rodea el elemento con comillas dobles</para>
 ''' <para> Ejemplo:</para>
 ''' <para> Valor inicial = [pegamento "maravilloso"].</para>
 ''' <para> Paso Uno: Duplicando comillas [pegamento ""maravilloso""].</para>
 ''' <para> Paso Dos: Rodeando con comillas ["pegamento ""maravilloso"""].</para>
 '''</remarks>
 ''' <exception cref="ArgumentNullException">
 '''    <para> El valor de <paramref name="matrizElementos" >
 '''           matrizElementos</paramref> </para> 
 '''    <para> o bien</para> 
 '''    <para> El valor de <paramref name="caracterSeparadorCampos" >
 '''           caracterSeparadorCampos</paramref></para> 
 '''    <para> es null (Nothing en Visual Basic</para> 
 ''' </exception>
 ''' <exception cref="ArgumentException">
 '''    <para> El valor de <paramref name="caracterSeparadorCampos" >
 '''           caracterSeparadorCampos</paramref>
 '''           es uno de los caracteres que no son válidos para actuar 
 '''           como separador de campos
 ''' </para> 
 ''' </exception>
 ''' <Copyright> 
 '''    <para> Copyright: Joaquin Medina Serrano [joaquin@medina.name]</para>
 '''    <para> Version .: [2009/03/15] </para>
 ''' </Copyright>
 Public Overloads Shared Function ToLineaCsv( _
             ByVal caracterSeparadorCampos As Char, _
             ByVal ParamArray matrizElementos() As String) _
             As String

     '-----------------------------------
     ' Control de parametros
     If matrizElementos Is Nothing Then
         Throw New ArgumentNullException( _
         "matrizElementos", _
         "El valor de la [matrizElementos()] es null" & _
         " (Nothing en Visual Basic)")
     End If
     ' si solo tiene un elemento y tiene el valor Nothing
     ' se devuelve una cadena vacia
     If matrizElementos.Length = 1 Then
         If matrizElementos(0) = Nothing Then
             Return String.Empty
         End If
     End If

     ' --------------------------------------
     'Control de los valores CORRECTOS mas frecuentes
     ' una coma(,) un punto y coma(;), un Pipe(|)
     If Not (caracterSeparadorCampos = ","c OrElse _
             caracterSeparadorCampos = ";"c OrElse _
             caracterSeparadorCampos = "|"c) Then
         Throw New ArgumentException( _
          "El [caracterSeparadorCampos] no es valido ", _
          "caracterSeparadorCampos")
     End If

     '-----------------------------------
     ' Definiendo variables
     Const QUOTE As Char = """"c
     Dim salida As String = String.Empty
     Dim aux As String = String.Empty
     Dim caracterAux As Char = Nothing
     Dim rodearConComillas As Boolean = False
     '-----------------------------------
     ' Proceso
     Try
         '-----------------------------------
         ' Recorrer la matriz para montar la cadena
         For i As Integer = matrizElementos.GetLowerBound(0) To _
                            matrizElementos.GetUpperBound(0)
             '-------
             ' en principio el texto va tal cual 
             rodearConComillas = False
             '-------
             ' obtener unelemento de la matriz
             aux = matrizElementos(i)
             '-----------------------------
             'MODIFICACIONES DEL TEXTO
             '-----------------------------
             ' caso uno 
             ' El elemento tiene el carácter separador, 
             ' rodear todo el texto con comillas dobles
             'ejemplo 5,34 --> "5,34"
             If aux.IndexOf(caracterSeparadorCampos) <> -1 Then
                 ' poner las comillas
                 rodearConComillas = True
             End If
 
             '-----------------
             ' caso dos
             ' Si el elemento tiene dobles comillas hay que 'escaparlas' 
             ' poniendo otra doble comilla junto a ella, y 
             ' después rodear todo el texto con comillas dobles
             ' ejemplo
             '      Venture "Extended Edition"
             '     "Venture ""Extended Edition"""
             If aux.IndexOf(QUOTE) <> -1 Then
                 ' no uso replace porque me da problemas
                 ' aux = aux.Replace(QUOTE, QUOTE & QUOTE)
                 Dim remplaza As String = String.Empty
                 For Each caracter As Char In aux
                     remplaza = remplaza & caracter
                     'doblar las comillas
                     If caracter = QUOTE Then
                         remplaza = remplaza & QUOTE
                     End If
                 Next
                 ' Valor modificado
                 aux = remplaza
                 ' poner las comillas
                 rodearConComillas = True
             End If

             '-----------------
             ' caso tres
             ' si el elemento contiene roturas de línea 
             ' rodear todo el texto con comillas dobles
             ' http://es.wikipedia.org/wiki/ASCII
             caracterAux = CType(Char.ConvertFromUtf32(10), Char) ' LF
             If aux.IndexOf(caracterAux) <> -1 Then
                 ' poner las comillas
                 rodearConComillas = True
             End If
             caracterAux = CType(Char.ConvertFromUtf32(13), Char) ' CR
             If aux.IndexOf(caracterAux) <> -1 Then
                 ' poner las comillas
                 rodearConComillas = True
             End If
 
             '-----------------
             ' caso cuatro
             ' si el elemento contiene espacios dentro de la cadena
             ' rodear todo el texto con comillas dobles
             If aux.IndexOf(" "c) <> -1 Then
                 ' poner las comillas
                 rodearConComillas = True
             End If

             '---------------------------------
             '---------------------------------
             'Rodear con comillas el texto
             If rodearConComillas = True Then
                 '-----------------------------
                 ' Si hay comillas rodeando no se hace nada
                 ' en caso contrario se ponen las comillas
                 ' ejemplo  5,34  --> "5,34"
                 ' ejemplo "5,34" --> no se hace nada
                 '-----------------------------
  
                 If Not (aux.Trim.StartsWith( _
                              QUOTE, _
                              StringComparison.CurrentCulture) AndAlso _
                         aux.Trim.EndsWith( _
                              QUOTE, _
                              StringComparison.CurrentCulture)) Then
                     ' poner las comillas
                     ' Observa que no elimino los espacios al poner las comillas
                     ' LOS ESPACIOS DE CADA ELEMENTO HAY QUE MANTENERLOS
                     '
                     ' Sin embargo, y únicamente en la interrogación,
                     ' elimino los espacios inciales y finales de la cadena
                     ' para ver si el elemento está rodeado o no de comillas
                     aux = QUOTE & aux & QUOTE
                 End If
             End If

             '-----------------------------
             ' OJO, el último elemento no lleva una coma (carácter separador)
             ' si solo hay un elemento  tampoco hay coma (carácter separador)
             ' El carácter separador de líneas es el salto de línea (CrLf)
             '-----------------------------
             If i = matrizElementos.GetUpperBound(0) Then
                 ' es el ultimo , Meter un fin de linea
                 salida = salida & aux & Environment.NewLine
             Else
                 salida = salida & aux & caracterSeparadorCampos
             End If
         Next
     Catch ex As Exception
         Throw
     Finally
         aux = Nothing
     End Try
     '-----------------------------------
     ' Devolver resultado obtenido
     Return salida
 End Function

 


↑↑↑

La Función LineaCsvToArray

Esta función es un poco más complicada, lo que hace es recibir una línea en formato CSV y separar sus componentes devolviéndolos cargados en una matriz de caracteres.

Ha resultado bastante más difícil de escribir de lo que parece porque el tratamiento de las comillas "huérfanas" o "duplicadas" puede llegar a convertirse en un autentico rompecabezas, y al final siempre hay algún caso que no lo resuelve. Un ejemplo, a modo de ejemplo, como separo un numero rodeado de comillas [ datos ,"25,36", "más datos"]

El problema con el que me he enfrentado es que la función tiene que responder a la siguiente baterías de pruebas sin equivocarse

Esta tabla está copiada.
La tabla original está en el documento siguiente: http://xbeat.net/vbspeed/c_ParseCSV.php
# CSV Valor 1 Valor 2 Valor 3
1 a,b,c a b c
2 "a",b,c a b c
3 'a',b,c 'a' b c
4   a  ,  b  ,  c     a     b     c  
5 aa,bb;cc aa bb;cc
6
7 a a
8 ,b, b
9 ,,c c
10 ,,
11 "",b b
12 " ",b   b
13 "a,b" a,b
14 "a,b",c a,b c
15 " a , b ", c   a , b   c 
16 a b,c a b c
17 a"b,c a"b c
18 "a""b",c a"b c
19 a""b,c a""b c
20 a,b",c a b" c
21 a,b"",c a b"" c
22 a,"B: ""Hi, I'm B""",c a B: "Hi, I'm B" c

Al final, después de desesperarme varias veces, encontré en [esta página] una solución muy elegante usando expresiones regulares. Y después de estudiarla y de una pequeña adaptación ha funcionado sin ningún problema


    ''' <summary>
    '''   Devuelve una matriz de cadenas con las subcadenas de la 
    '''   cadena pasada por parámetro que están delimitadas por el 
    '''   caracterSeparadorCampos especificado. 
    ''' </summary>
    ''' <param name="caracterSeparadorCampos">
    '''   El carácter que se va a utilizar como separador de campos
    ''' </param>
    ''' <param name="lineaConFormatoCsv">
    '''    Cadena a analizar, la cadena  que vamos a partir
    ''' </param>
    ''' <returns>
    '''    Una matriz cuyos elementos contienen las subcadenas de 
    '''    <paramref name="lineaConFormatoCsv" >
    '''    lineaConFormatoCsv</paramref>  
    '''    que están delimitadas 
    '''    por el <paramref name="caracterSeparadorCampos" >
    '''    caracterSeparadorCampos</paramref>.
    ''' </returns>
    ''' <remarks>
    '''  <para> 
    '''     El [caracterSeparadorCampos] no se incluye en los 
    '''     elementos de la matriz devuelta.
    '''  </para>
    '''  <para> 
    '''     Si la cadena no contiene ningun [caracterSeparadorCampos], 
    '''     la matriz devuelta estará formada por un solo elemento 
    '''     que contiene la cadena. 
    ''' </para>
    '''  <para> 
    '''     Si la [lineaParaAnalizar] esta vacía (empty), 
    '''     la matriz devuelta estará formada por un solo 
    '''     elemento que contiene el valor [Empty]. 
    ''' </para>
    '''  <para> 
    '''     Si dos delimitadores son adyacentes o el delimitador 
    '''     se encuentra al principio o al final de la [lineaParaAnalizar], 
    '''     el elemento de matriz correspondiente contiene Empty. 
    ''' </para>
    '''  <para>
    '''     Si hay comillas rodeando una subcadenas, hay que
    '''     quitarlas. Ejemplo ["5,34"] --> 5,34 
    ''' </para>
    '''  <para>
    '''     Si una subcadenas contiene dos comillas dobles 
    '''     seguidas, se sustituyen por una sola
    ''' </para>
    '''  <para>ejemplo</para>
    '''  <para>  subcadena de entrada ..= Venture ""Extended Edition""</para>
    '''  <para>  salida generada .......= Venture "Extended Edition"</para>
    ''' <example>
    ''' 
    '''</example>
    ''' <code> 
    '''   Esta función esta inspirada en el código que 
    '''   se encuentra en la página 
    '''   http://xbeat.net/vbspeed/c_ParseCSV.php
    ''' </code>
    '''</remarks>
    ''' <exception cref="ArgumentNullException">
    '''    <para> El valor de <paramref name="lineaConFormatoCsv" >
    '''           lineaConFormatoCsv</paramref> </para> 
    '''    <para> o bien</para> 
    '''    <para> El valor de <paramref name="caracterSeparadorCampos" >
    '''           caracterSeparadorCampos</paramref></para> 
    '''    <para> es null (Nothing en Visual Basic</para> 
    ''' </exception>
    ''' <exception cref="ArgumentException">
    '''    <para> El valor de <paramref name="caracterSeparadorCampos" >
    '''           caracterSeparadorCampos</paramref>
    '''           es uno de los caracteres que no son válidos para actuar 
    '''           como separador de campos
    ''' </para> 
    ''' </exception>
    ''' <Copyright> 
    '''    <para> Copyright: Joaquin Medina Serrano [joaquin@medina.name]</para>
    '''    <para> Version .: [2009/03/15] </para>
    ''' </Copyright>
    Public Overloads Shared Function LineaCsvToArray( _
               ByVal caracterSeparadorCampos As Char, _
               ByVal lineaConFormatoCsv As String) _
               As String()

        '-----------------------------------
        ' Control de parámetros
        If lineaConFormatoCsv Is Nothing Then
            Throw New ArgumentNullException( _
            "lineaConFormatoCsv", _
            "El valor de la [matrizElementos()] " & _
            "es null (Nothing en Visual Basic)")
        End If

        If lineaConFormatoCsv.Length = 0 Then
            Dim auxBorrar As String() = {String.Empty}
            Return auxBorrar
        End If

        ' --------------------------------------
        'Control de los valores CORRECTOS mas frecuentes
        ' una coma(,) un punto y coma(;), un Pipe(|)
        If Not (caracterSeparadorCampos = ","c OrElse _
                caracterSeparadorCampos = ";"c OrElse _
                caracterSeparadorCampos = "|"c) Then
            Throw New ArgumentException( _
             "El [caracterSeparadorCampos] no es valido ", _
             "caracterSeparadorCampos")
        End If

        '-----------------------------------
        ' Definiendo variables
        '-----------------------
        Const QUOTE As Char = """"c
        Dim arrayDatosIndividuales As String() = Nothing
        '-----------------------

        Dim objRegEx As  _
            System.Text.RegularExpressions.Regex = Nothing
        Dim objMatchCollection As  _
            System.Text.RegularExpressions.MatchCollection = Nothing
        Dim objMatch As  _
            System.Text.RegularExpressions.Match = Nothing
        '-----------------------
        Dim indice As Integer = 0
        Dim Aux As String = String.Empty
        '-------------------------------------------------------------
        ' Cadena para separar utilizando la coma como separador
        ' Dim patron As String = "(\s*""[^""]*""\s*,)|(\s*[^,]*\s*,)"
        '-------------------------------------------------------------
        ' Cadena modificada para que acepte cualquier separador
        Dim patron As String = _
                 "(\s*""[^""]*""\s*" & caracterSeparadorCampos & _
                 ")|(\s*[^" & caracterSeparadorCampos & "]*\s*" & _
                 caracterSeparadorCampos & ")"

        '-----------------------------------
        ' Proceso
        Try
            objRegEx = New System.Text.RegularExpressions.Regex( _
                       patron, _
                       System.Text.RegularExpressions.RegexOptions.IgnoreCase)

            objMatchCollection = _
                objRegEx.Matches(lineaConFormatoCsv & caracterSeparadorCampos)

            '  Definir la matriz para los datos de salida
            ReDim arrayDatosIndividuales(objMatchCollection.Count - 1)
            For Each objMatch In objMatchCollection
                '-----
                ' Obtener un elemento
                Aux = objMatch.Value.Substring(0, objMatch.Length - 1)
                '-----------------------------
                ' ---> Si hay comillas rodeando el valor hay que quitarlas
                ' ejemplo ["5,34"] --> 5,34 
                ' Problema = Que haya un espacio delante o detrás de la comilla
                ' ejemplo [ " 5,34" ] --> 5,34 
                '-----------------------------
                If Aux.Trim.StartsWith( _
                       QUOTE, _
                       StringComparison.CurrentCulture) AndAlso _
                   Aux.Trim.EndsWith( _
                       QUOTE, _
                       StringComparison.CurrentCulture) Then
                    Aux = Aux.Trim
                    Aux = Aux.Substring(1, Aux.Length - 2)
                    ' ---- >Segundo asunto
                    ' Dos comillas dobles seguidas, sustituirlas por una sola
                    ' ejemplo
                    '     Venture ""Extended Edition""
                    '     Venture "Extended Edition"
                    Aux = Aux.Replace(QUOTE & QUOTE, QUOTE)

                End If
                '-----
                ' Añadirlo a la matriz de salida
                arrayDatosIndividuales(indice) = Aux
                indice += 1
            Next objMatch

        Catch ex As Exception
            Throw
        Finally
            If objRegEx IsNot Nothing Then
                objRegEx = Nothing
            End If
            If objMatchCollection IsNot Nothing Then
                objMatchCollection = Nothing
            End If
            If objMatch IsNot Nothing Then
                objMatch = Nothing
            End If
            indice = Nothing
            patron = Nothing
            Aux = Nothing
        End Try
        '-----------------------------------
        ' Devolver resultado obtenido
        Return arrayDatosIndividuales

    End Function
		


↑↑↑

Para Finalizar

Una vez que el código funcionaba, he hecho una pequeña modificación para que acepte cualquier carácter como separador ( puede verse la modificación de la cadena [patrón] de la expresión regular, porque la cadena original esta comentada), y entonces aparece el problema de la consistencia de datos, es decir, si estoy volcando texto a formato CSV, no puedo emplear letras ni números como separadores de datos, por esa razón, he escrito una función que limita los caracteres de separación a los que me han parecido mas lógicos. La limitación la he realizado de forma excluyente, es decir, no permito caracteres de control, aquellos cuyo valor ASCII sea inferior a 32, excepto el carácter tabulador horizontal que tiene el valor ASCII = 8. Tampoco permito letras, ni números, ni el carácter [Esc] . Puedes ver dicha modificación en el código que acompaña a este artículo.


↑↑↑

A.1.Referencias

RFC-4180
Common Format and MIME Type for Comma-Separated Values (CSV) Files
  • Información del documento:
    • Fecha.: [2005-10-01T00:00:00]
    • Resumen.: This RFC documents the format used for Comma-Separated Values (CSV) files and registers the associated MIME type "text/csv". This memo provides information for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited.
  • URL del enlace: http://tools.ietf.org/html/rfc4180
CSV
Wikipedia - CSV
  • Información del documento:
    • Fecha.: [2009-02-17T00:00:00]
    • Título.: CSV
    • Resumen.: Los ficheros CSV (del inglés comma-separated values) son un tipo de documento sencillo para representar datos en forma de tabla, en las que las columnas se separan por comas (o punto y coma en donde la coma es el separador decimal: España, Francia, Italia...) y las filas por saltos de línea. Los campos que contengan una coma, un salto de línea o una comilla doble deben ser encerrados entre comillas dobles.
  • URL del enlace: http://es.wikipedia.org/wiki/CSV
CTX
CTX - Creativyst Table Exchange Format
  • Información del documento:
    • Fecha.: [2008-01-01T00:00:00]
    • Resumen.: This article specifies CTX, a simple, shared, low-overhead exchange format. It can be used for simple tasks, such as exchanging rows of a single table without header information, up to more complex tasks, like exchanging multiple tables, along with their field names, types and comments. It will also facilitate the exchange of complex hierarchical data structures. CTX is a more precisely defined and functional alternative to CSV, and a lower overhead alternative to many applications of XML. The
  • URL del enlace: http://www.creativyst.com/Doc/Std/ctx/ctx.htm

Espacios de nombres usados en el código de este artículo:

System.Text.RegularExpressions

 



Compromiso del autor del artículo con el sitio del Guille:

Lo comentado en este artículo está probado (y funciona) con la siguiente configuración:

El autor se compromete personalmente de que lo expuesto en este artículo es cierto y lo ha comprobado usando la configuración indicada anteriormente.

En cualquier caso, el Guille no se responsabiliza del contenido de este artículo.

Si encuentras alguna errata o fallo en algún link (enlace), por favor comunícalo usando este link:

Gracias.


Código de ejemplo (comprimido):

 

Fichero con el código de ejemplo: jms32_Csv_SolutionCSV - 32.00 KB

(MD5 checksum: 5F09AA07B93B986C6892346D664393B8)

 


Ir al índice principal de el Guille