De CSV a JSON: los cinco casos que rompen cualquier conversor
Publicado el 17/7/2026 · 15 min de lectura · Herramientas para desarrolladores
Daniel Okonkwo — Desarrollador front-end y redactor de Tecnología en OneKitly
Rendimiento web · Formatos de archivo
Verificado con 4 fuentes
El CSV no tiene norma, solo el RFC 4180: un RFC informativo que describe lo que ya hacían casi todos los programas en 2005, no una regla obligatoria. Cinco casos separan un analizador que funciona de uno que corrompe en silencio. Uno: un delimitador dentro de un campo entrecomillado. name,city / Tom,"Paris, France" se queda en dos columnas, y una comilla doblada dentro sale como una sola. Dos: un salto de línea dentro de un campo entrecomillado. El analizador lee hasta la comilla de cierre y no hasta el fin de línea, así que una dirección de dos líneas sobrevive como un único valor. Tres: los tipos. La conversión viene desactivada; actívala y 1 pasa a ser el número 1, mientras que 0044, 1.0, 1e3, 2026-08-18 y 9007199254740993 siguen siendo cadenas, porque una celda solo se convierte si el número se vuelve a imprimir exactamente como llegó. true pasa a booleano pero TRUE no, porque los booleanos JSON van en minúscula, y null pasa a null de JSON, lo que sorprende el día en que un apellido es Null. Cuatro: cabeceras duplicadas. name,name,name da name, name_2 y name_3 en vez de una sola columna superviviente, y una cabecera vacía se convierte en column2. Cinco: la codificación. Se quita el BOM UTF-8, y el navegador absorbe los BOM de UTF-8 y UTF-16 antes de que la herramienta vea el texto, pero no hay selector de codificación, así que una exportación Windows-1252 llega como Andr�, y U+FFFD no se deshace. Dos casos que no salva: un campo entrecomillado precedido de un espacio, Tom, "Paris, France", no se trata como entrecomillado, y una línea de pista de Excel sep=; se consume como cabecera.
Delimitadores entrecomillados, saltos de línea incrustados, tipos ambiguos, cabeceras duplicadas y codificación. Cada caso se pasó por el conversor y aquí está la salida exacta, incluidos los dos que no salva.
El RFC 4180 es una descripción, no una regla
Todo el mundo cita el RFC 4180 como si fuera la norma del CSV. Su propia portada dice lo contrario: es informativo, lo que en lenguaje IETF significa que no especifica ninguna norma de Internet. Se publicó en 2005 para dejar por escrito lo que los programas ya hacían, y lo dice de su propio objeto: la regla 5 señala que algunos programas, Microsoft Excel entre ellos, no usan comillas dobles en absoluto. Ahí está la raíz de todos los problemas de este artículo. No hay autoridad a la que apelar cuando dos herramientas discrepan sobre el mismo archivo, porque ninguna infringe nada.
El RFC sí define dos cosas que ayudarían, y ninguna sobrevive al paso por un archivo. Define un parámetro header en el tipo de medio text/csv, con los valores present y absent, para indicar al receptor si la primera fila son nombres de columna. Y dice que el uso habitual es US-ASCII, con otros juegos de caracteres transportados por el parámetro charset. Ambos son parámetros MIME: viven en una respuesta HTTP o en un adjunto, no dentro de los bytes. Guarda los mismos datos como ventas.csv y las dos informaciones han desaparecido. Por eso cualquier lector de CSV del mundo ofrece una casilla «la primera fila es cabecera», y por eso hay que adivinar la codificación.
Casos 1 y 2 — el delimitador y el salto de línea dentro de un campo entrecomillado
Estos dos son el mismo error con distinto disfraz, y ambos vienen de partir por el carácter en bruto en lugar de analizar. Un conversor que hace text.split(",") convierte Tom,"Paris, France" en tres columnas, y todas las filas de debajo heredan la columna de más. Un conversor que hace primero text.split("\n") corta en dos una dirección de dos líneas y produce una fila con un solo campo. El remedio es el mismo: recorrer la cadena carácter a carácter, llevar una bandera de «estoy dentro de comillas», y tratar un delimitador o un salto de línea como estructural solo cuando la bandera está bajada.
Los dos pasan. name,address / Tom,"12 rue A\nParis" / Ann,"3 rue B" devuelve exactamente dos objetos, el primero con una dirección de dos líneas. Una comilla doblada se desescapa a la entrada, así que "He said ""hi"" loudly" vuelve como He said "hi" loudly. Una desviación respecto al RFC conviene conocerla: la herramienta normaliza todo CR LF a LF antes de analizar, así que un salto de línea que era CR LF dentro de un campo entrecomillado sale del conversor como LF suelto. No se pierde nada, pero si comparas el viaje de ida y vuelta byte a byte, ahí está la diferencia.
El caso que no salva es aquel sobre el que el RFC es explícito. La sección 2.4 dice que los espacios forman parte del campo y no deben ignorarse: en Tom, "Paris, France" el primer carácter del campo es un espacio y la comilla que sigue es solo un carácter, no un delimitador de apertura. El analizador le da la razón al RFC y produce dos columnas rotas, " Paris y France". La mayoría de quien escribe esa línea quería un campo entrecomillado. Si tu exportador pone un espacio tras el delimitador, quítalo antes de convertir o las comillas son decorativas.
Caso 3 — los tipos, y la prueba de ida y vuelta que salva tus teléfonos
El CSV no tiene tipos. Cada celda es texto, y en cuanto produces JSON hay que decidir si 1 es la cadena "1" o el número 1. Por defecto el conversor no decide nada: la conversión es un interruptor y arranca apagado, así que una ejecución simple te da un array de objetos cuyos valores son todos cadenas. Es el valor por defecto correcto, porque una cadena siempre se puede recuperar y un número no.
Enciende el interruptor y la regla es una sola prueba de ida y vuelta: una celda se convierte en número solo si volver a imprimir ese número devuelve exactamente los caracteres que llegaron. Al ejecutarlo, 1 pasa a 1, pero 0044 se queda en "0044" porque Number("0044") se imprime 44. 1.0 se queda en "1.0" porque se imprime 1. 1e3 se queda en "1e3" porque se imprime 1000. .5 y +1 siguen siendo cadenas por lo mismo. Y 9007199254740993 sigue siendo cadena, porque el double más cercano de JavaScript se imprime 9007199254740992: un conversor sin esta protección cambia en silencio el último dígito de un identificador largo, y nada aguas abajo te lo dirá.
Tres cosas escapan a la prueba de ida y vuelta, porque van por comparación literal. true y false pasan a booleanos, pero solo en minúscula: TRUE, True y FALSE siguen siendo cadenas, lo que importa porque Excel escribe los booleanos en mayúscula y las interfaces francesa y alemana escriben VRAI y WAHR. null pasa al null de JSON, y ahí hay una trampa real: un campo de texto cuyo valor son las cuatro letras null no es lo mismo que un valor ausente, y tras la conversión ya no puedes distinguirlos. Y con las fechas no se hace nada: 2026-08-18 sigue siendo la cadena "2026-08-18", que es la respuesta correcta, porque un conversor que analiza fechas tiene que elegir una zona horaria y se equivocará.
Caso 4 — cabeceras duplicadas, cabeceras vacías, filas irregulares
Un CSV puede repetir un nombre de columna; un objeto JSON no. Con name,name,name sobre a,b,c, la implementación ingenua escribe tres veces la misma clave y JSON se queda con la última: obtienes {"name": "c"} y dos columnas de datos han desaparecido sin ningún error. Este conversor renombra: name, name_2, name_3. También cubre el caso siguiente, cuando el nombre inventado choca con uno real: name,name,name_2 da name, name_2 y name_2_2, porque el renombrador comprueba contra todo lo ya usado y no solo contra las cabeceras originales.
Una celda de cabecera vacía recibe un nombre posicional: name,,name, sobre a,b,c,d da name, column2, name_2 y column4. Los nombres de cabecera se recortan, así que " name , age " produce name y age. Y el ancho de salida es el de la fila más ancha del archivo, no el de la cabecera: a,b,c sobre las dos filas 1,2 y 3,4,5,6 da cuatro claves a cada objeto, con c vacía en la fila corta y un column4 que lleva el 6 que la cabecera nunca contempló. No se descarta nada, y es la decisión correcta para un conversor: truncar en silencio una fila larga es destruir justo la fila que había que mirar.
Caso 5 — la codificación, la que la herramienta no puede arreglar
Un archivo CSV son bytes. Nada dentro dice qué tabla convierte esos bytes en caracteres, y el RFC 4180 pone esa información en un parámetro MIME que un archivo en disco no lleva. Dos mecanismos cubren en parte el hueco. Una marca de orden de bytes al principio del archivo identifica UTF-8, UTF-16 LE y UTF-16 BE, y el lector de archivos del navegador la consume: suelta un archivo UTF-16 LE con BOM en la herramienta y el texto llega bien decodificado, con la marca ya quitada. La herramienta vuelve a quitar un BOM por su cuenta, lo que cubre el caso en que la marca llega por el portapapeles y no por un archivo.
El hueco que queda abierto es el archivo sin marca alguna, que son la mayoría. Guarda una hoja de cálculo como CSV simple en una máquina Windows de Europa occidental y obtienes Windows-1252, un byte por carácter, sin BOM. Este conversor no tiene selector de codificación: el lector cae a UTF-8, el byte E9 que significaba é no es UTF-8 válido, y se sustituye por U+FFFD. La herramienta analiza luego sin problemas y devuelve {"name": "Andr�", "city": "K�ln"} sin aviso alguno, porque desde su punto de vista nada ha fallado. U+FFFD no guarda registro del byte que sustituyó, así que no es reparable a posteriori: vuelve a exportar el archivo como UTF-8, o pega el texto en lugar de soltar el archivo, porque el texto del portapapeles ya lo ha decodificado la aplicación que lo posee.
Un último caso de codificación tiene el filo afilado: UTF-16 sin marca de orden de bytes. No hay nada que olfatear, así que el archivo se lee como UTF-8, uno de cada dos bytes es un cero, y lo que vuelve es un único objeto cuya clave contiene caracteres NUL. Parece basura y no texto ligeramente equivocado, y ese es el buen desenlace: lo verás enseguida. Los fallos peligrosos son los silenciosos, y Windows-1252 leído como UTF-8 es el más silencioso de todos, porque las columnas encajan a la perfección y solo las letras acentuadas están mal.
El sexto caso que nadie enumera: la línea sep=
Excel acepta una primera línea con la forma sep=; como instrucción sobre qué carácter separa los campos, y muchas rutinas de exportación la emiten para que un archivo con punto y coma se abra bien en un lector cuyo separador de listas es la coma. No está en el RFC 4180 y nunca estuvo: es una convención de fabricante que se extendió porque funciona. Para un conversor que nunca ha oído hablar de ella, es simplemente el primer registro del archivo.
Es exactamente lo que pasa aquí. Dale al conversor sep=; seguido de Name;Ville;Montant y dos filas de datos: la detección automática elige correctamente el punto y coma —porque la línea sep= contiene uno— pero el paso de cabecera se la come. Obtienes tres objetos en vez de dos, con las claves "sep=", column2 y column3, y los nombres reales de columna Name, Ville y Montant aparecen como valores del primero. Es evidente en cuanto miras la salida, e invisible si la encadenas directamente a otra cosa. Borra la primera línea antes de convertir, o convierte primero el delimitador y deja que el conversor de delimitador reescriba la pista por ti.
| Entrada | Lo que sale | Por qué |
|---|---|---|
| Tom,"Paris, France" | Dos campos: Tom y Paris, France | El analizador sigue un estado «entre comillas»; un delimitador citado es dato |
| Tom, "Paris, France" (espacio tras la coma) | Tres campos: Tom, " Paris y France" | RFC 4180 sección 2.4: el espacio forma parte del campo, así que la comilla no abre nada |
| 0044 con la conversión de tipos activada | La cadena "0044" | Number("0044") se imprime 44, que no es lo que llegó, así que la celda se deja igual |
| TRUE con la conversión de tipos activada | La cadena "TRUE"; solo true en minúsculas pasa a booleano | La prueba es una comparación literal con las dos palabras clave JSON, que van en minúscula |
| name,name,name sobre a,b,c | Claves name, name_2 y name_3 — se conservan los tres valores | Una clave repetida en un objeto destruye datos: la segunda y la tercera se renombran |
| Un archivo Windows-1252 soltado en la herramienta | Andr� y K�ln, analizados sin problema y sin aviso | No hay selector de codificación: el lector supone UTF-8 y sustituye cada byte inválido |
| Un archivo que empieza por sep=; | El punto y coma se detecta bien, pero sep= pasa a ser la primera clave y la cabecera real pasa a fila de datos | La pista es una convención de Excel, ajena a cualquier definición de CSV: el analizador la lee como un registro |
Preguntas frecuentes
- ¿Activo la conversión de tipos o la dejo apagada?
- Déjala apagada salvo que algo aguas abajo necesite números de verdad. Una cadena es una representación sin pérdida de lo que había en la celda; un número es una representación con pérdida, y la pérdida es irreversible. La protección de ida y vuelta hace que esta herramienta concreta no estropee 0044, 1.0 ni un identificador de 19 dígitos, pero sí convertirá una columna de códigos postales sin cero inicial: 75001 y 75008 pasan a números mientras que un código neerlandés como 1012 AB sigue siendo cadena —una columna, dos tipos, y quien consuma el JSON tiene que manejar ambos—. Si necesitas números, convierte después las columnas que te importan, donde puedes nombrarlas, en lugar de dejar que una heurística decida columna a columna.
- ¿Cómo sabe el conversor que mi archivo usa punto y coma?
- Cuenta los delimitadores candidatos —coma, punto y coma, tabulación y barra vertical— solo en el primer registro, saltándose lo que esté entre comillas, y se queda con el más frecuente. Leer solo el primer registro es deliberado: una cabecera como "Nom;Prénom" no debe puntuarse por una coma enterrada en una dirección entrecomillada trescientas filas más abajo. La limitación es el espejo de eso. Si tu cabecera contiene una coma y tus filas de datos usan punto y coma, el detector elige la coma y cada fila pasa a ser un único campo. Dos síntomas lo delatan al instante: una sola clave por objeto, y una clave cuyo nombre es toda la línea de cabecera. Ante la duda, fija el delimitador de forma explícita en lugar de fiarte de la detección.
- ¿Por qué mis caracteres acentuados se han vuelto interrogaciones o rombos negros?
- Porque el archivo no era UTF-8 y nada se lo dijo al lector. El rombo negro con interrogación es U+FFFD, el carácter de reemplazo de Unicode, y es lo que emite un decodificador cuando una secuencia de bytes no es válida en la codificación que le mandaron suponer. Tu archivo era casi seguro Windows-1252 o ISO 8859-1, donde é es el byte único E9; UTF-8 necesita dos bytes para é, y E9 solo no es el inicio legal de nada. El daño ocurre antes de que corra el analizador CSV, así que ningún ajuste de CSV lo deshará. Abre el original en un editor que te deje elegir la codificación, guárdalo como UTF-8 y vuelve a convertir. Si el archivo viene de una hoja de cálculo, expórtalo con la opción UTF-8 en lugar de CSV simple.
- Mis filas no tienen todas el mismo número de campos. ¿Se perderán datos?
- No. El ancho de salida es el de la fila más ancha del archivo, incluidas las filas más anchas que la cabecera. Una fila corta recibe cadenas vacías para las columnas que faltan; una fila larga recibe claves extra llamadas column4, column5 y así para los campos que la cabecera nunca nombró. No se trunca nada, y eso importa: una fila demasiado larga suele ser el síntoma de un delimitador sin escapar más arriba, y truncar borraría la prueba. Si ves column4 en tu JSON y tu cabecera solo tenía tres nombres, busca un campo con un delimitador sin comillas: ahí es donde el archivo se torció.
- ¿Existe una versión de CSV sin estos problemas?
- Dentro del propio CSV no, porque el formato no tiene dónde poner los metadatos que zanjarían las preguntas. Lo que sí existe son convenciones puestas encima: un archivo de esquema que acompaña y nombra las columnas y sus tipos, un perfil de exportación fijo acordado entre los dos sistemas, o un formato que lleva sus propios tipos. Si controlas los dos extremos, JSON Lines —un objeto JSON por línea— resuelve de golpe las comillas, los saltos de línea y los tipos, a cambio de un archivo más grande que no se abre en una hoja de cálculo. Si no controlas los dos extremos, la respuesta práctica es ser aburrido: UTF-8 con BOM, coma o punto y coma de forma constante, todos los campos entrecomillados, sin línea sep=, y una cabecera con nombres únicos y sin el delimitador.
Artículos que podrían interesarte
Todas las guías →Herramientas relacionadas
Esto describe lo que hacen estos conversores hoy, comprobado ejecutándolos, y no lo que una norma obligue a hacer a un conversor. El CSV no tiene norma prescriptiva: el RFC 4180 es informativo y describe una práctica habitual, así que dos herramientas aparentemente correctas pueden discrepar sobre el mismo archivo sin que ninguna se equivoque. El aplanado, la detección de tipos y la de arrays son convenciones, no reglas. Antes de convertir datos que no puedas volver a exportar, pasa primero por una copia y compara el número de filas y columnas en ambos extremos.
Fuentes
- IETF — RFC 4180, Common Format and MIME Type for Comma-Separated Values (CSV) Files, October 2005 — Informational, not a standard: section 2 rules 5 to 7 on double quotes, section 2.4 on spaces being part of a field, and the header and charset parameters of the text/csv media type
- IETF — RFC 8259, The JavaScript Object Notation (JSON) Data Interchange Format, December 2017 — section 4 on object member names being unordered and the consequences when names repeat, and section 6 on the interoperability limits of numbers
- WHATWG — Encoding Standard — the decoder algorithms, the BOM sniffing rules, and the use of U+FFFD as the replacement for a byte sequence that is not valid in the chosen encoding
- W3C — File API — the read operation and its encoding determination: an explicit encoding, then the blob's charset parameter, then a byte order mark, then UTF-8 as the fallback
¿Has detectado un error en este artículo?