Interroga el archivo antes de parsearlo.
Este es el módulo que justifica la librería. La especificación que manda el
cliente y el archivo que manda el banco son dos documentos distintos, y la
diferencia se descubre siempre tarde: después de escribir el parser, en la
primera corrida con datos reales, un viernes. detectar/2 mueve ese
descubrimiento al día uno.
iex> {:ok, reporte} = AnchoFijo.Detector.detectar("12345678-9JUAN PEREZ \n98765432-1ANA SOTO \n")
iex> {reporte.largo_consistente?, reporte.largo_predominante, reporte.terminador}
{true, 22, :lf}
iex> reporte.probablemente_ancho_fijo?
trueY el caso que más veces salva el proyecto: el archivo que dijeron que era de ancho fijo y no lo es.
iex> {:ok, reporte} = AnchoFijo.Detector.detectar("juan;100\nmaria;20000\n")
iex> reporte.probablemente_ancho_fijo?
false
iex> reporte.delimitador_sugerido
";"El reporte
Un mapa con estas claves:
:lineas_analizadas— líneas con contenido consideradas.:lineas_vacias— líneas en blanco encontradas y excluidas del análisis.:muestra_truncada?— si se leyó solo parte del archivo.:largos— frecuencia de cada largo de línea en bytes,%{120 => 18}.:largo_consistente?—truesi hay un solo largo.:largo_predominante— el largo más frecuente, onilsi no hay líneas.:largos_en_caracteres— igual que:largospero en caracteres, solo si el archivo es UTF-8 con multibyte;nilen otro caso.:encoding_probable—:ascii,:utf8o:latin1.:bytes_no_utf8— hasta cinco bytes que rompen UTF-8, con línea y posición.:terminador—:crlf,:lf,:cr,:mixtoo:ninguno.:termina_con_terminador?—nilsi la muestra está truncada.:delimitadores— análisis de;,,, tab y|.:delimitador_sugerido— el delimitador que sugiere que el archivo es delimitado, onil.:probablemente_ancho_fijo?— el veredicto, resumido.:observaciones— el reporte en prosa, para pegar en un correo.
Opciones
:lineas— máximo de líneas a analizar. Default 200.:bytes— máximo de bytes a leer del archivo. Default 64.000.:desde—:auto(default),:archivoo:contenido, para desambiguar si el binario es una ruta o el contenido mismo.:layout— unAnchoFijo.Layouto una definición, para contrastar lo que el archivo dice con lo que la especificación declara.:delimitadores— lista de candidatos a delimitador. Default[";", ",", "\t", "|"].
Summary
Functions
Contrasta un reporte con un layout y devuelve los desacuerdos como diagnósticos.
Analiza una muestra y devuelve el reporte.
Types
@type reporte() :: %{ lineas_analizadas: non_neg_integer(), lineas_vacias: non_neg_integer(), muestra_truncada?: boolean(), largos: %{optional(non_neg_integer()) => pos_integer()}, largo_consistente?: boolean(), largo_predominante: non_neg_integer() | nil, largos_en_caracteres: %{optional(non_neg_integer()) => pos_integer()} | nil, encoding_probable: :ascii | :utf8 | :latin1, bytes_no_utf8: [map()], terminador: :crlf | :lf | :cr | :mixto | :ninguno, termina_con_terminador?: boolean() | nil, delimitadores: %{optional(String.t()) => map()}, delimitador_sugerido: String.t() | nil, probablemente_ancho_fijo?: boolean(), observaciones: [String.t()] }
Functions
@spec contrastar(reporte(), AnchoFijo.Layout.t() | Enumerable.t()) :: [ AnchoFijo.Diagnostico.t() ]
Contrasta un reporte con un layout y devuelve los desacuerdos como diagnósticos.
Es la pregunta "¿esto es realmente lo que me dijeron que es?" en forma de función. Una lista vacía significa que el archivo y la especificación concuerdan en lo que se puede verificar sin parsear.
iex> {:ok, reporte} = AnchoFijo.Detector.detectar("ABCDEFGH\nIJKLMNOP\n")
iex> layout = AnchoFijo.Layout.nuevo!(campos: [[nombre: :a, largo: 10]])
iex> [diagnostico] = AnchoFijo.Detector.contrastar(reporte, layout)
iex> AnchoFijo.Diagnostico.mensaje(diagnostico)
"entrada: se esperaba un largo de línea de 10 bytes según el layout, llegó 8; el archivo tiene 2 bytes menos por línea: falta un campo, o el layout es de otra versión del formato"
iex> {:ok, reporte} = AnchoFijo.Detector.detectar("ABCDEFGH\nIJKLMNOP\n")
iex> AnchoFijo.Detector.contrastar(reporte, AnchoFijo.Layout.nuevo!(campos: [[nombre: :a, largo: 8]]))
[]
@spec detectar( term(), keyword() ) :: {:ok, reporte()} | {:error, [AnchoFijo.Diagnostico.t()]}
Analiza una muestra y devuelve el reporte.
Acepta el contenido como binario, una ruta a un archivo o —vía :desde— la
desambiguación explícita entre ambos.
iex> {:ok, reporte} = AnchoFijo.Detector.detectar("AAAA\nBBB\n")
iex> reporte.largos
%{3 => 1, 4 => 1}
iex> reporte.largo_consistente?
falseUn archivo en latin-1 se delata solo:
iex> {:ok, reporte} = AnchoFijo.Detector.detectar(<<74, 79, 83, 201, 10>>)
iex> reporte.encoding_probable
:latin1
iex> hd(reporte.bytes_no_utf8)
%{linea: 1, posicion: 4, byte: 201}