txt texto saber online detectar como codificacion cambiar archivo c# asp.net csv text-parsing

c# - texto - detectar codificacion online



¿Cómo debo detectar qué delimitador se usa en un archivo de texto? (13)

Necesito poder analizar archivos CSV y TSV. No puedo confiar en que los usuarios sepan la diferencia, por lo que me gustaría evitar pedirle al usuario que seleccione el tipo. ¿Hay una manera simple de detectar qué delimitador está en uso?

Una forma sería leer en cada línea y contar tanto las pestañas como las comas y averiguar cuál se usa de manera más consistente en cada línea. Por supuesto, los datos podrían incluir comas o pestañas, por lo que puede ser más fácil decirlo que hacerlo.

Editar: Otro aspecto divertido de este proyecto es que también necesitaré detectar el esquema del archivo cuando lo leí porque podría ser uno de muchos. Esto significa que no sabré cuántos campos tengo hasta que pueda analizarlos.


¿Sabes cuántos campos deben estar presentes por línea? Si es así, leería las primeras líneas del archivo y verificaría en función de eso.

En mi experiencia, los datos "normales" a menudo contienen comas pero rara vez contienen caracteres de pestañas. Esto sugeriría que debe verificar la cantidad constante de pestañas en las primeras líneas e ir con esa opción como una suposición preferida. Por supuesto, depende exactamente de qué datos tienes.

En última instancia, sería muy posible tener un archivo que sea completamente válido para ambos formatos, por lo que no puede ser absolutamente infalible. Tendrá que ser un trabajo de "mejor esfuerzo".


En Python, hay una clase Sniffer en el módulo csv que se puede utilizar para adivinar el delimitador de un archivo dado y los caracteres de comillas. Su estrategia es (citada de docstrings de csv.py):

[Primero, busque] texto entre dos citas idénticas (la cita probable) precedidas y seguidas por el mismo carácter (el delimitador probable). Por ejemplo:

,''some text'',

La cita con más victorias, igual con el delimitador. Si no hay comillas, el delimitador no se puede determinar de esta manera.

En ese caso, intente lo siguiente:

El delimitador debe aparecer la misma cantidad de veces en cada fila. Sin embargo, debido a datos malformados, puede que no. No queremos un enfoque de todo o nada, por lo que permitimos pequeñas variaciones en este número.

  1. construye una tabla de la frecuencia de cada personaje en cada línea.
  2. construir una tabla de frecuencias de esta frecuencia (meta-frecuencia?), por ejemplo, ''x ocurrió 5 veces en 10 filas, 6 veces en 1000 filas, 7 veces en 2 filas''
  3. usa el modo de meta-frecuencia para determinar la frecuencia esperada para ese personaje
  4. averiguar con qué frecuencia el personaje realmente cumple ese objetivo
  5. el personaje que mejor cumple con su objetivo es el delimitador

Por motivos de rendimiento, los datos se evalúan en fragmentos, por lo que pueden probar y evaluar la menor parte posible de los datos, evaluando fragmentos adicionales según sea necesario.

No voy a citar aquí el código fuente; está en el directorio Lib de cada instalación de Python.

Recuerde que CSV también puede usar punto y coma en lugar de comas como delimitadores (por ejemplo, en las versiones alemanas de Excel, los CSV están delimitados por punto y coma porque las comas se utilizan como separadores de decimales en Alemania ...)


En mi experiencia, los datos rara vez contienen pestañas, por lo que una línea de campos delimitados por tabulaciones sería (en general) bastante obvia.

Sin embargo, las comas son más difíciles, especialmente si estás leyendo datos en lugares no estadounidenses. Los datos numéricos pueden contener un gran número de comas si está leyendo archivos generados fuera del país, ya que los números en coma flotante a menudo los contienen.

Al final, lo único seguro es, por lo general, intentarlo, presentárselo al usuario y permitirle que se ajuste, especialmente si sus datos contienen comas y / o pestañas.


Está en PHP, pero parece ser bastante confiable:

$csv = ''something;something;something someotherthing;someotherthing;someotherthing ''; $candidates = array('','', '';'', "/t"); $csvlines = explode("/n", $csv); foreach ($candidates as $candidatekey => $candidate) { $lastcnt = 0; foreach ($csvlines as $csvline) { if (strlen($csvline) <= 2) continue; $thiscnt = substr_count($csvline, $candidate); if (($thiscnt == 0) || ($thiscnt != $lastcnt) && ($lastcnt != 0)) { unset($candidates[$candidatekey]); break; } $lastcnt = $thiscnt; } } $delim = array_shift($candidates); echo $delim;

Lo que hace es lo siguiente: para cada delimitador posible especificado, lee cada línea en el CSV y comprueba si la cantidad de veces que se produce cada separador es constante. Si no, el separador candidato se elimina y, en última instancia, debe terminar con un separador.


Me encontré con una necesidad similar y pensé que compartiría lo que se me ocurrió. Aún no he procesado muchos datos, por lo que hay posibles casos extremos. Además, tenga en cuenta que el objetivo de esta función no es el 100% de certeza del delimitador, pero es mejor adivinar para ser presentado al usuario.

/// <summary> /// Analyze the given lines of text and try to determine the correct delimiter used. If multiple /// candidate delimiters are found, the highest frequency delimiter will be returned. /// </summary> /// <example> /// string discoveredDelimiter = DetectDelimiter(dataLines, new char[] { ''/t'', ''|'', '','', '':'', '';'' }); /// </example> /// <param name="lines">Lines to inspect</param> /// <param name="delimiters">Delimiters to search for</param> /// <returns>The most probable delimiter by usage, or null if none found.</returns> public string DetectDelimiter(IEnumerable<string> lines, IEnumerable<char> delimiters) { Dictionary<char, int> delimFrequency = new Dictionary<char, int>(); // Setup our frequency tracker for given delimiters delimiters.ToList().ForEach(curDelim => delimFrequency.Add(curDelim, 0) ); // Get a total sum of all occurrences of each delimiter in the given lines delimFrequency.ToList().ForEach(curDelim => delimFrequency[curDelim.Key] = lines.Sum(line => line.Count(p => p == curDelim.Key)) ); // Find delimiters that have a frequency evenly divisible by the number of lines // (correct & consistent usage) and order them by largest frequency var possibleDelimiters = delimFrequency .Where(f => f.Value > 0 && f.Value % lines.Count() == 0) .OrderByDescending(f => f.Value) .ToList(); // If more than one possible delimiter found, return the most used one if (possibleDelimiters.Any()) { return possibleDelimiters.First().Key.ToString(); } else { return null; } }


Me imagino que su solución sugerida sería la mejor manera de hacerlo. En un archivo CSV o TSV bien formado, el número de comas o pestañas respectivamente por línea debe ser constante (sin variación). Haga un recuento de cada una de las líneas del archivo y compruebe cuál es constante para todas las líneas. Parecería bastante improbable que el recuento de ambos delímetros para cada línea sea idéntico, pero en este caso inconcebiblemente raro, podría, por supuesto, avisar al usuario.

Si ni el número de pestañas ni las comas son constantes, muestre un mensaje al usuario indicándole que el archivo está mal formado pero el programa cree que es un archivo (el formato tiene la desviación estándar más baja de delímetros por línea).


No hay una forma "eficiente".


Podría mostrarles los resultados en la ventana de vista previa, de forma similar a como lo hace Excel. Está bastante claro cuando se utiliza el delimitador incorrecto en ese caso. Luego podría permitirles seleccionar un rango de delimitadores y tener la actualización de la vista previa en tiempo real.

Entonces podría hacer una simple suposición sobre el delimitador para comenzar (por ejemplo, si una coma o una pestaña son las primeras).


Puede verificar si una línea está usando un delimitador u otro como este:

while ((line = readFile.ReadLine()) != null) { if (line.Split(''/t'').Length > line.Split('','').Length) // tab delimited or comma delimited? row = line.Split(''/t''); else row = line.Split('',''); parsedData.Add(row); }


Simplemente lea algunas líneas, cuente el número de comas y el número de pestañas y compárelas. Si hay 20 comas y ninguna pestaña, está en CSV. Si hay 20 pestañas y 2 comas (tal vez en los datos), está en TSV.


Supongo que en el texto normal, las pestañas son muy raras, excepto como primer carácter (s) en una línea: piense en párrafos con sangría o código fuente. Creo que si encuentras pestañas incrustadas (es decir, aquellas que no siguen a las comas), puedes asumir que las pestañas se usan como delimitadores y son correctas la mayor parte del tiempo. Esto es solo un presentimiento, no verificado con ninguna investigación. Por supuesto, le daría al usuario la opción de anular el modo calculado automáticamente.


Suponiendo que hay un número fijo de campos por línea y que las comas o pestañas dentro de los valores están entre comillas ("), usted debería poder calcular la frecuencia de cada carácter en cada línea. t fijo, esto es más difícil, y si las comillas no se usan para encerrar de otro modo los caracteres de delimitación, será, sospecho, casi imposible (y dependiendo de los datos, específicos de la configuración regional).


Suponiendo que tienes un conjunto estándar de columnas, esperarás ...

Utilizaría FileHelper (proyecto de código abierto en SourceForge). http://filehelpers.sourceforge.net/

Defina dos plantillas de lector, una para comas, una para pestañas.

Si el primero falla, intente con el segundo.