Todas las guías

Guías de TSV y CSV

CRLF vs LF — fines de línea en archivos de datos

El fin de línea es la única diferencia entre dos archivos por lo demás idénticos byte a byte, y la que nadie mira hasta que falla una búsqueda solo en la última columna.

Cada fila de un archivo de texto termina con algo, y hay tres candidatos para ese algo. Son invisibles, no son intercambiables, y mezclarlos en un mismo archivo es tan común como fácil de hacer sin querer.

La forma habitual de enterarte es curiosamente concreta: todo funciona salvo la última columna, donde ningún valor coincide.

Los tres finales

  • LF — un byte, 0x0A. Unix, Linux y macOS desde OS X. Se escribe \n.
  • CRLF — dos bytes, 0x0D 0x0A. Windows, y también el formato de cable de las cabeceras HTTP y del correo. Se escribe \r\n. El RFC 4180, la especificación de CSV, pide CRLF — cosa que sorprende a quien da por hecho que LF es la opción neutra.
  • CR — un byte, 0x0D, solo. Mac OS clásico, hasta la versión 9. Hoy no vas a producir uno, pero exportaciones antiguas y algunos sistemas heredados los siguen emitiendo, y un analizador que solo parta por \n ve ese archivo como una única línea enorme.

Nada dentro del archivo anuncia cuál se está usando. Se deduce mirando, que es por lo que las herramientas no se ponen de acuerdo.

¿Por qué solo se rompe la última columna?

Este es el síntoma que conviene reconocer, porque identifica el problema él solo.

Un archivo se escribe con CRLF. Algo lo lee y parte las filas solo por \n. Todas las filas quedan bien separadas — pero el \r que iba antes de cada \n no formaba parte del separador, así que se queda pegado al final de la fila. El último campo de esa fila termina ahora en un retorno de carro que nadie dibuja.

Así que "activo" en la última columna es en realidad "activo\r". Falla en cualquier comparación, se imprime idéntico en cualquier registro y sobrevive al copiado. Es un problema de caracteres invisibles con una causa estructural, y buscar un pegado descuidado no lo va a encontrar.

La pista es que afecta a la última columna y solo a ella, en todas las filas, de manera uniforme. Los espacios que pega una persona nunca son tan ordenados.

Cómo acaba un archivo mezclado

Un mismo archivo con más de un estilo es la situación que más confunde a las herramientas, y llega por vías de lo más normales:

  • Filas añadidas por otra herramienta. La exportación original escribió CRLF, un script añadió cuarenta filas con LF, y ahora el archivo tiene los dos.
  • Una edición en el editor equivocado. Unos editores conservan los finales que ya tenía el archivo y otros aplican el suyo a las líneas que tocas.
  • La fusión de dos exportaciones de dos sistemas distintos.
  • Una celda que contiene un salto de línea. Un campo entrecomillado con un salto dentro es legítimo, y un detector ingenuo lo cuenta como prueba de otro estilo. No es una mezcla en absoluto, pero las herramientas la reportarán como tal.

Los finales mezclados merecen reportarse y rara vez merecen alarma. La reparación es elegir uno y reescribir de forma coherente — pero elige a conciencia, porque lo que consuma el archivo después puede tener su propia opinión.

Git, y el diff que lo cambió todo

La forma más común de perder una tarde con esto no tiene nada que ver con analizar archivos.

Git en Windows suele venir con core.autocrlf=true, que convierte LF en CRLF cuando los archivos aterrizan en tu directorio de trabajo y de vuelta a LF cuando confirmas. Para código fuente esto es invisible y útil. Para un archivo de datos significa que los bytes del disco no son los bytes del repositorio.

El síntoma es un diff que afirma que cambiaron todas las líneas de un archivo de 50 000 filas cuando editaste una celda. Lo que cambió son los fines de línea, en todo el archivo, porque algo lo reescribió con el otro estilo.

El arreglo es un .gitattributes que diga qué es el archivo:

*.tsv text eol=lf
*.csv text eol=lf

O, cuando el archivo debe conservar exactamente los bytes que tiene y Git no debe interpretarlo en absoluto:

*.tsv -text

Ponlo antes de confirmar el archivo, no después. Cambiarlo más tarde lo reescribe otra vez, lo que produce un diff enorme más.

Elegir uno, y el salto de línea final

Para un archivo que se queda dentro de una cadena de herramientas Unix o multiplataforma, LF. Para un archivo que va a software de Windows o a un compañero que lo abrirá en Excel, CRLF es la apuesta más segura y es lo que pide la especificación de CSV.

Hay una cuarta decisión escondida al lado de esta: si la última fila termina con un fin de línea o no. POSIX dice que la última línea de un archivo de texto va terminada, y las herramientas lo dan por hecho — wc -l cuenta de menos un archivo sin él, y concatenar dos archivos así pega la última fila del primero con la cabecera del segundo.

La regla que importa más que cualquiera de las dos elecciones: un archivo que solo estás editando debe volver con los finales con los que llegó. Una reparación que además convierte CRLF en LF en silencio ha cambiado 50 000 líneas para arreglar una celda, y ha roto el archivo para lo que venga a leerlo.

Hacerlo aquí

El editor de este sitio detecta el fin de línea al abrir, cuenta cada estilo por separado y muestra el resultado en la barra de estado en vez de darlo por supuesto. Si hay más de un estilo te lo dice, y distingue una mezcla de verdad de un salto de línea dentro de una celda entrecomillada, que no es lo mismo.

Para TSV y CSV, el diálogo ofrece LF o CRLF entre registros, o el ajuste importado (incluido CR), además del salto final. Por defecto conserva un fin de línea uniforme y la presencia o ausencia de salto final. Si los finales están mezclados, usa el más frecuente; en empates prioriza CRLF, después LF y CR. Los saltos dentro de las celdas no cambian. Por ejemplo, a,b\r\nc,d\ne,f sale con CRLF en los dos separadores de registro y sin salto final. Las comillas y la codificación pueden cambiar: editar una celda no garantiza que solo cambie una línea.

No se sube nada: el archivo lo lee y lo escribe tu navegador.