c# - read - CSV Parsing
read csv file c# example (13)
Acabo de probar tu expresión regular en mi código ... funciona bien para texto formateado con cita ...
pero me pregunto si podemos analizar el valor por debajo de Regex ...
"First_Bat7679",""NAME","ENAME","FILE"","","","From: "DDD,_Ala%as"@sib.com"
Estoy buscando resultados como:
''First_Bat7679'' ''"NAME","ENAME","FILE"'' '''' '''' ''From: "DDD,_Ala%as"@sib.com''
Gracias
Estoy tratando de usar C # para analizar CSV. Usé expresiones regulares para encontrar ","
y leí la cadena si mi conteo de encabezados era igual a mi recuento de coincidencias.
Ahora esto no funcionará si tengo un valor como:
"a",""b","x","y"","c"
entonces mi salida es:
''a''
''"b''
''x''
''y"''
''c''
pero lo que quiero es:
''a''
''"b","x","y"''
''c''
¿Hay alguna expresión regular o cualquier otra lógica que pueda usar para esto?
Bueno, no soy un experto en expresiones regulares, pero estoy seguro de que tienen una respuesta para esto.
Procesalmente está yendo letra por letra. Establezca una variable, digamos dontMatch, en FALSE.
Cada vez que te topas con una cotización, alternar dontMatch.
cada vez que te topas con una coma, marca dontMatch. Si es VERDADERO, ignora la coma. Si es FALSO, divídelo en la coma.
Esto funciona para el ejemplo que das, pero la lógica que utilizas para las comillas es fundamentalmente defectuosa: debes escapar de ellas o usar otro delimitador (comillas simples, por ejemplo) para separar las comillas principales de las citas menores.
Por ejemplo,
"a", ""b", ""c", "d"", "e""
rendirá malos resultados.
Esto se puede arreglar con otro parche. En lugar de simplemente mantener un verdadero falso, tienes que hacer coincidir las comillas.
Para que coincida con las comillas, debes saber lo que se vio por última vez, lo que te lleva a un territorio de análisis bastante profundo. Probablemente, en ese momento, querrá asegurarse de que su lenguaje esté bien diseñado, y si es así, puede usar una herramienta de compilación para crear un analizador para usted.
-Adán
CSV, cuando se trata de elementos como delimitadores de varias líneas, citado, diferentes * etc., puede ser más complicado de lo que se piensa ... ¿quizás considerar una respuesta prelaminada? Yo uso esto , y funciona muy bien.
* = recuerde que algunas configuraciones regionales usan [tab] como C en CSV ...
El analizador de CSV de Lumenworks (de código abierto, gratuito pero necesita un inicio de sesión de proyecto de código) es de lejos el mejor que he utilizado. Le ahorrará tener que escribir la expresión regular y es intuitivo de usar.
Para tener un archivo CSV analizable, cualquier comilla doble dentro de un valor debe ser escapada de alguna manera. Las dos formas estándar de hacerlo son mediante la representación de una comilla doble, ya sea como dos comillas dobles seguidas o una comilla doble invertida. Esa es una de las siguientes dos formas:
""
/ "
En la segunda forma, su cadena inicial se vería así:
"a", "/" b / ", /" x / ", /" y / "", "c"
Si su cadena de entrada no está formateada en un formato riguroso como este, tiene muy pocas posibilidades de analizarlo correctamente en un entorno automatizado.
Si se garantiza que todos sus valores están entre comillas, busque valores, no para comas:
("".*?""|"[^"]*")
Esto aprovecha el hecho de que "gana el emparejamiento más antiguo": primero busca los valores de cotización doble y con una prioridad más baja para los valores cotizados normales.
Si no desea que la cita adjunta sea parte de la coincidencia, use:
"(".*?"|[^"]*)"
e ir por el valor en el grupo de coincidencia 1.
Como dije: Requisito previo para que esto funcione es una entrada bien formada con cotizaciones garantizadas o comillas dobles alrededor de cada valor. ¡Los valores vacíos deben ser citados también! Un buen efecto secundario es que no le importa el carácter separador. Comas, TABs, punto y coma, espacios, lo que sea. Todo funcionará.
Vea el enlace "Regex Fun with CSV" en:
Yo usaría FileHelpers si fuera tú. Las expresiones regulares son buenas pero difíciles de leer, especialmente si regresas, después de un tiempo, para una solución rápida.
Solo por el ejercicio de mi mente, el procedimiento C # de trabajo rápido y sucio:
public static List<string> SplitCSV(string line)
{
if (string.IsNullOrEmpty(line))
throw new ArgumentException();
List<string> result = new List<string>();
bool inQuote = false;
StringBuilder val = new StringBuilder();
// parse line
foreach (var t in line.Split('',''))
{
int count = t.Count(c => c == ''"'');
if (count > 2 && !inQuote)
{
inQuote = true;
val.Append(t);
val.Append('','');
continue;
}
if (count > 2 && inQuote)
{
inQuote = false;
val.Append(t);
result.Add(val.ToString());
continue;
}
if (count == 2 && !inQuote)
{
result.Add(t);
continue;
}
if (count == 2 && inQuote)
{
val.Append(t);
val.Append('','');
continue;
}
}
// remove quotation
for (int i = 0; i < result.Count; i++)
{
string t = result[i];
result[i] = t.Substring(1, t.Length - 2);
}
return result;
}
FileHelpers for .Net es tu amigo.
CSV es un gran ejemplo para la reutilización de código: no importa cuál de los analizadores csv que elija, no elija el suyo. Deje de rodar su propio analizador CSV
Hay un dicho frecuentemente citado:
Algunas personas, cuando se enfrentan con un problema, piensan "Lo sé, usaré expresiones regulares". Ahora ellos tienen dos problemas. (Jamie Zawinski)
Dado que no hay un estándar oficial para los archivos CSV (en cambio, hay una gran cantidad de estilos ligeramente incompatibles), debe asegurarse de que lo que implemente se adapte a los archivos que recibirá. No tiene sentido implementar nada más elegante que lo que necesita, y estoy seguro de que no necesita expresiones regulares.
Aquí está mi puñalada sobre un método simple para extraer los términos: básicamente, recorre la línea buscando comas, manteniendo un registro de si el índice actual está dentro de una cadena o no:
public IEnumerable<string> SplitCSV(string line)
{
int index = 0;
int start = 0;
bool inString = false;
foreach (char c in line)
{
switch (c)
{
case ''"'':
inString = !inString;
break;
case '','':
if (!inString)
{
yield return line.Substring(start, index - start);
start = index + 1;
}
break;
}
index++;
}
if (start < index)
yield return line.Substring(start, index - start);
}
Advertencia estándar: código no probado, puede haber errores uno a uno.
Limitaciones
Las comillas alrededor de un valor no se eliminan automáticamente.
Para hacer esto, agregue una marca justo antes de la declaración deyield return
cerca del final.Las comillas simples no son compatibles de la misma manera que las comillas dobles
Puede agregar un valor booleano por separado eninSingleQuotedString
, cambiar el nombre del booleano existente ainDoubleQuotedString
y tratar ambos de la misma manera. (No puede hacer que el booleano existente doble funcione porque necesita que la cadena termine con la misma cita que la inició).El espacio en blanco no se elimina automáticamente
Algunas herramientas introducen espacios en blanco alrededor de las comas en archivos CSV para "bonito" el archivo; luego se vuelve difícil decir que el espacio en blanco intencional formatee el espacio en blanco.
FileHelpers admite campos de líneas múltiples .
Puede analizar archivos como estos:
a,"line 1
line 2
line 3"
b,"line 1
line 2
line 3"
Aquí está la declaración de tipo de datos:
[DelimitedRecord(",")]
public class MyRecord
{
public string field1;
[FieldQuoted(''"'', QuoteMode.OptionalForRead, MultilineMode.AllowForRead)]
public string field2;
}
Aquí está el uso:
static void Main()
{
FileHelperEngine engine = new FileHelperEngine(typeof(MyRecord));
MyRecord[] res = engine.ReadFile("file.csv");
}
Pruebe CsvHelper (una biblioteca que mantengo) o FastCsvReader . Ambos funcionan bien. CsvHelper también escribe. Como todos los demás han estado diciendo, no hagas lo tuyo. :PAG