Ir al contenido
OneKitly

Convertir entre formatos de lista sin perder datos: las reglas de comillas que nadie lee

Publicado el 30/6/2025 · 14 min de lectura · Herramientas de texto e idioma

Daniel Okonkwo

Daniel OkonkwoDesarrollador front-end y redactor de Tecnología en OneKitly

Rendimiento web · Formatos de archivo

Verificado con 6 fuentes

Ver perfil
En resumen

Pasar de una lista con saltos de línea a una lista con comas es una línea de código hasta que un elemento contiene una coma. Tres nombres — García, Ana / López, Luis / O’Shea, Iván — unidos por comas y vueltos a cortar dan seis elementos, no tres. El remedio es una regla de comillas, y la que hay que seguir es la RFC 4180: un campo que contenga una coma, una comilla doble o un salto de línea debe ir entre comillas dobles, y una comilla doble dentro de un campo entrecomillado se escapa duplicándola. Escrito así, "García, Ana","López, Luis","O’Shea, Iván" se vuelve a leer como exactamente tres elementos. Dos consecuencias sorprenden. Un campo CSV puede contener legalmente un salto de línea: un fichero con dos registros puede ocupar tres líneas físicas, y cortarlo por el carácter de fin de línea es sencillamente erróneo — los registros se separan con CRLF y solo un analizador de verdad sabe qué saltos cuentan. Y una cadena vacía no es cero elementos: cortar «» por la coma devuelve un elemento vacío, mientras que unir [] y unir [""] producen ambos la cadena vacía, de modo que esas dos listas se vuelven indistinguibles si no se entrecomillan todos los campos. Nunca conviertas con un simple corte por el delimitador.

Pasar de una lista con saltos de línea a una lista con comas es trivial hasta que un elemento contiene una coma. Las reglas de comillas de la RFC 4180, por qué un campo CSV puede contener un salto de línea, por qué las hojas de cálculo europeas usan el punto y coma, y qué le hace un elemento vacío a la ida y vuelta — cada caso ejecutado e impreso.

La línea de código y el momento exacto en que se rompe

Lista con saltos de línea a lista con comas: es una unión. A la inversa: un corte. Ambas son correctas exactamente mientras ningún elemento contenga el delimitador, y en cuanto uno lo contiene la conversión deja de ser reversible sin decirlo. Nuestra lista de prueba de cinco elementos — Smith, John / Doe, Jane / O’Neill, «Bud» / una dirección de dos líneas / plain — unida por comas y vuelta a cortar devolvió ocho elementos. Nada lanzó una excepción, nada avisó, y tres de los ocho eran fragmentos de nombres. Ese silencio es todo el problema: un conversor de listas que pierde datos produce una lista plausible, no un error.

El mismo experimento en cada una de nuestras lenguas da la misma forma: tres entradas «apellido, nombre» se convierten en seis tras una ida y vuelta ingenua, en inglés, francés, español, portugués, alemán e italiano por igual. Escritas con un generador RFC 4180 y releídas con un analizador RFC 4180, todas vuelven como tres elementos idénticos a la entrada. La regla no es propia de una lengua; solo lo son los datos que la hacen tropezar.

Lo que dice de verdad la RFC 4180

La RFC 4180 es corta, de octubre de 2005 y — conviene saberlo — Informational, no una norma. Sus siete reglas: los registros se separan con CRLF; el último no necesita terminar con uno; puede haber una línea de cabecera opcional al principio; los campos se separan con comas y los espacios forman parte del campo; entrecomillar es opcional, pero un campo sin comillas no puede contener una comilla doble; los campos que contienen saltos de línea, comillas dobles o comas deben ir entre comillas dobles; y una comilla doble dentro de un campo entrecomillado se escapa anteponiéndole otra comilla doble. Esa última regla es la que la gente sustituye por un invento, normalmente una barra invertida, que ningún lector de CSV espera.

La gramática ABNF de la sección 2 es más estricta que cualquier uso real. TEXTDATA se define como %x20-21 / %x23-2B / %x2D-7E, lo que excluye la coma en %x2C y la comilla doble en %x22 — y también todo byte por encima de 127. Lo comprobamos: «plain» es conforme a TEXTDATA; «café», «naïve», «Straße» y «ação» no lo son. En la práctica el parámetro charset del tipo de medio text/csv lleva la codificación y todo el mundo escribe UTF-8, pero recuerda que la RFC codificó un desorden existente en lugar de diseñar un formato. El propio documento lo dice al recomendar ser conservador en lo que se produce y liberal en lo que se acepta.

Un campo CSV puede contener un salto de línea

Es la regla que rompe más importadores, porque contradice el modelo mental de un registro por línea. Escribimos un fichero de dos registros cuyo segundo campo es una dirección de dos líneas: los bytes son id-1,"Line one CRLF Line two",ok CRLF id-2,flat,ok. Cortado por el salto de línea da tres fragmentos; analizado correctamente da dos registros, el primero de los cuales contiene el salto intacto. Cualquier código que lea un CSV con readLines está mal ante esta entrada, y la entrada no es exótica — direcciones, descripciones de producto y notas pegadas contienen saltos de línea.

Los finales de línea merecen su propio párrafo. La RFC exige CRLF entre registros, y cortar «a,b CRLF c,d CRLF» solo por el salto de línea devuelve ["a,b\r", "c,d\r", ""] — dos campos con un retorno de carro invisible pegado y una cola vacía. Ese \r suelto explica que un valor se compare distinto de sí mismo entre dos sistemas y que una cadena vacía final se convierta en una última fila fantasma. Un analizador que consuma CRLF, LF y un CR aislado como separadores de registro maneja las tres familias de ficheros y devuelve los mismos dos registros para cada una.

Por qué media Europa escribe CSV con punto y coma

Pregunta a la plataforma qué aspecto tiene un número en cada una de nuestras seis locales y la colisión salta a la vista. Formatear 1234567.5 da 1,234,567.5 en en-US, 1 234 567,5 en fr-FR con un espacio fino irrompible U+202F como separador de grupos, 1.234.567,5 en es-ES, de-DE e it-IT, y 1 234 567,5 en pt-PT con U+00A0. Cinco de las seis usan la coma como marca decimal. Una lista de precios delimitada por comas en esas locales tiene por tanto una coma dentro de un campo en cada fila — y por eso mismo sus hojas de cálculo escriben y esperan el punto y coma.

La ejecución lo hace concreto. La fila Silla / 1.299,00 / 2 unida por comas se analiza como cuatro campos — Silla, 1.299, 00, 2 — porque la marca decimal es una coma en español. La fila Chair / 1,299.00 / 2 se analiza también como cuatro por la razón especular: el separador de miles es una coma en inglés. Entrecomilla el campo de precio y ambas vuelven a ser tres campos; usa un punto y coma y ambas son tres campos sin ninguna comilla. Ninguna vía es más correcta: el punto y coma es la que una hoja de cálculo europea abre sin diálogo de importación, y las comas entrecomilladas la que aceptará una API.

Elementos vacíos, separadores finales y lo que ninguna ida y vuelta puede recuperar

Cortar la cadena vacía por la coma devuelve un elemento vacío, no cero. «a,b,» devuelve tres elementos, el último vacío. «,a» devuelve dos, el primero vacío. «a,,b» devuelve tres, el del medio vacío. Ninguno es un error; todos son consecuencia de una sola definición — un separador separa, así que n separadores significan n+1 elementos. Lo que la gente suele querer es la versión filtrada, y filtrar es una decisión que borra en silencio un campo genuinamente vacío.

El caso irrecuperable está en la escritura. Unir la lista vacía y unir una lista con una cadena vacía producen ambas la cadena vacía, así que las dos son idénticas en el cable y ningún analizador puede distinguirlas. Nuestro propio analizador mínimo lo agravó: al leer la cadena vacía devolvía cero registros, lo cual es correcto para una de las dos entradas y falso para la otra. Cambiar a un generador que entrecomilla todos los campos lo arregla exactamente: un elemento vacío pasa a ser los dos caracteres "" y se relee como un único elemento vacío, mientras que cero elementos siguen siendo la cadena vacía y se releen como nada. Si en tus datos pueden aparecer elementos vacíos, entrecomillar siempre no es una cuestión de estilo.

JSON, tabuladores y elegir un delimitador a propósito

Un array JSON esquiva toda la discusión entrecomillando todo y escapando el resto: nuestra lista de cinco elementos sobrevivió a la ida y vuelta sin cambios, con la dirección de dos líneas guardada como una sola cadena que contiene \n. Es el formato a elegir cuando hay un programa en ambos extremos. Su coste es que todo consumidor debe ser un analizador JSON, y que JSON tiene tipos — una lista de códigos postales vuelve como números si alguien los escribe sin comillas, y 01234 vuelve como 1234 o como error de sintaxis.

Los valores separados por tabuladores son el formato sin especificación, y por eso funcionan tantas veces y fallan tan callados. Nuestra lista adversa contenía un tabulador dentro de un elemento, así que un delimitador de tabulador lo habría partido. Antes de elegir delimitador, mira: en esa lista la coma, el punto y coma y el tabulador aparecían dentro de elementos, mientras que la barra vertical, U+001F y el byte nulo no. Un delimitador que demostrablemente no aparece devuelve la conversión a la línea de código que parecía al principio — y si ninguno es seguro, entrecomilla. Una última nota práctica ajena al análisis: un campo que empieza por =, +, - o @ lo trata como fórmula una hoja de cálculo, así que una lista de cadenas suministradas por usuarios debe llevar esos campos neutralizados antes de que nadie abra el fichero.

La misma lista de tres elementos a través de cinco formatos, ejecuciones en Node 26.3.0. Elementos: García, Ana / López, Luis / O’Shea, Iván. Solo los formatos con una regla de comillas o de escape sobreviven a un elemento que contiene el delimitador.
FormatoSeparador de elementosSeparador dentro de un elementoSalto de línea dentro de un elementoElementos tras la ida y vuelta
Un elemento por líneaSalto de líneaSin problema — las comas son caracteres ordinariosImposible — termina el elemento3 de 3
Unión ingenua por comasComa, sin comillasRompe — el elemento se parte en dosRompe — parece un registro nuevo6 de 3
CSV RFC 4180Coma, campos entrecomillados si hace faltaEntrecomillar el campoLegal dentro de un campo entrecomillado3 de 3
CSV con punto y coma (hojas de cálculo europeas)Punto y comaMisma regla de comillas, otro delimitadorLegal dentro de un campo entrecomillado3 de 3
Array JSONComa entre cadenas entrecomilladasSin problema — toda cadena va entrecomilladaEscapado como \n3 de 3
Separado por tabuladoresTabuladorSeguro solo si ningún elemento contiene un tabulador — el nuestro lo conteníaNo definido por ninguna norma3 de 3 solo con suerte
Conversor de formato de listaConvierte una lista entre viñetas, números y líneas simples.Probar la herramienta

Preguntas frecuentes

¿Un campo CSV puede contener de verdad un salto de línea?
Sí, y la RFC 4180 lo dice explícitamente: un campo que contenga saltos de línea debe ir entre comillas dobles, y la ABNF permite CR y LF dentro de un campo escapado. Escribimos un fichero de dos registros cuyo segundo campo tenía una dirección de dos líneas; ocupa tres líneas físicas, así que contar líneas da 3 y analizar da 2. Cualquier importador basado en leer líneas está mal ante ese fichero.
¿Un fichero delimitado por punto y coma sigue siendo CSV?
Según la RFC 4180 no, porque su ABNF fija el delimitador en %x2C, la coma. En la práctica es lo que escriben las hojas de cálculo en toda locale que use la coma decimal — cinco de nuestras seis. Conserva el resto de las reglas: entrecomilla los campos que contengan el delimitador, duplica las comillas, separa los registros con CRLF. Nombra el fichero con honestidad e indica el delimitador al entregarlo.
¿Una cadena vacía es un elemento o cero?
El corte dice uno: cortar «» por la coma devuelve una lista con un elemento vacío. La unión no puede decirlo, porque [] y [""] producen ambas la cadena vacía. Así que la respuesta es una convención que hay que elegir y anotar, no algo que contengan los datos. La única forma de conservar la distinción en una ida y vuelta es entrecomillar todos los campos, lo que convierte un elemento vacío en dos comillas y cero elementos en nada.
¿Cómo escapo una comilla doble dentro de un campo?
Duplicándola, dentro de un campo entrecomillado. El elemento say "hi" se escribe "say ""hi""" — una comilla de apertura, el texto con cada comilla interior escrita dos veces, una comilla de cierre. La barra invertida no hace nada: CSV no tiene escape por barra invertida. Nuestra lista adversa de once elementos, que incluía esa cadena y otra ya entrecomillada, hizo la ida y vuelta idéntica bajo esta regla.
¿Cuándo debería usar mejor un array JSON?
Siempre que en ambos extremos haya programas. JSON entrecomilla cada cadena y escapa los caracteres de control, así que los elementos con comas, comillas y saltos de línea no requieren trato especial: nuestra lista de cinco elementos hizo la ida y vuelta sin cambios, con el elemento de dos líneas guardado con \n dentro de una sola cadena. Prefiere CSV cuando al otro lado haya una hoja de cálculo o una persona, y recuerda que JSON tiene tipos: los identificadores con cero inicial deben seguir siendo cadenas.

Artículos que podrían interesarte

Todas las guías
ExplicaciónDónde puede cortarse una línea: el algoritmo Unicode detrás de cada párrafo ajustado«Cortar en los espacios» falla en la mayoría de los sistemas de escritura. UAX #14 da a cada carácter una clase de corte de línea; buscamos las nuestras en Unicode 17.0.0 y ejecutamos una implementación conforme sobre espacios duros, guiones blandos, espacios de ancho cero, URL, japonés y tailandés.ExplicaciónFrecuencia de palabras y ley de Zipf: contamos seis libros en seis lenguas y ajustamos la pendienteLa palabra de rango n aparece unas 1/n veces respecto a la primera. Contamos seis libros de dominio público, imprimimos rango × frecuencia, ajustamos log frecuencia contra log rango y obtuvimos pendientes entre -1,02 y -1,08 en las seis lenguas — y los dos sitios donde la ley falla.GuíaLas listas de tareas en Markdown y qué se renderiza de verdad en cada sitioLas listas de tareas no están en CommonMark. Son una extensión de GitHub Flavored Markdown, y por eso el mismo fichero muestra casillas en un sitio y corchetes literales en otro. La regla exacta del marcador, qué hace el anidamiento y una tabla de qué es CommonMark, qué es GFM y qué no es ninguno — comprobado contra ambas especificaciones y cuatro renderizadores.TutorialFiltrar líneas por un patrón sin línea de comandosEsto es grep para quien no usa grep, con una diferencia importante: la búsqueda es una subcadena literal, así que una expresión regular de verdad devuelve un cuadro vacío y ningún error. Cada afirmación se comprobó ejecutando la herramienta.GuíaFormatear números para seis idiomas: separadores, moneda y la vuelta al valor1.234,56 y 1,234.56 son el mismo número, y confundirlos cambia el valor que lee un lector. Ejecutamos Intl.NumberFormat para las seis locales del sitio e imprimimos cada separador —incluido el invisible que usa el francés— y luego medimos por qué parseFloat no puede deshacer nada de eso.ExplicaciónLos emoji son más difíciles de lo que parecen: por qué «basta con quitarlos» no tiene respuesta en una líneaUn emoji visible puede valer un punto de código o catorce unidades UTF-16. Lanzamos tres expresiones regulares populares sobre una frase real y cada una falló de otra forma; una borró los dígitos. Aquí está el porqué, qué propiedad Unicode responde a qué pregunta, y la regla de grupos de grafemas que sí funciona.

Herramientas relacionadas

Fuentes

¿Has detectado un error en este artículo?

Convertir entre formatos de lista sin perder datos: las reglas de comillas que nadie lee — OneKitly