Es ist schwierig, CSV-Dateien zu analysieren, wenn die CSV-Datei entweder durch Kommas getrennte Zeichenfolgen, durch Kommas getrennte Zeichenfolgen in Anführungszeichen oder eine chaotische Kombination der beiden sein kann. Die von mir entwickelte Lösung ermöglicht eine der drei Möglichkeiten.
Ich habe eine Methode erstellt, ParseCsvRow (), die ein Array aus einer CSV-Zeichenfolge zurückgibt. Ich beschäftige mich zuerst mit doppelten Anführungszeichen in der Zeichenfolge, indem ich die Zeichenfolge in doppelte Anführungszeichen in ein Array namens quoteArray aufteile. CSV-Dateien mit Anführungszeichen sind nur gültig, wenn eine gerade Anzahl von doppelten Anführungszeichen vorhanden ist. Doppelte Anführungszeichen in einem Spaltenwert sollten durch ein Paar doppelter Anführungszeichen ersetzt werden (dies ist der Ansatz von Excel). Solange die CSV-Datei diese Anforderungen erfüllt, können Sie davon ausgehen, dass die Trennzeichen nur außerhalb von doppelten Anführungszeichen angezeigt werden. Kommas in doppelten Anführungszeichen sind Teil des Spaltenwerts und sollten beim Aufteilen der CSV-Datei in ein Array ignoriert werden.
Meine Methode prüft Kommas außerhalb von Paaren mit doppelten Anführungszeichen, indem sie nur gerade Indizes des Anführungszeichenarrays betrachtet. Außerdem werden doppelte Anführungszeichen am Anfang und am Ende von Spaltenwerten entfernt.
public static string[] ParseCsvRow(string csvrow)
{
const string obscureCharacter = "ᖳ";
if (csvrow.Contains(obscureCharacter)) throw new Exception("Error: csv row may not contain the " + obscureCharacter + " character");
var unicodeSeparatedString = "";
var quotesArray = csvrow.Split('"'); // Split string on double quote character
if (quotesArray.Length > 1)
{
for (var i = 0; i < quotesArray.Length; i++)
{
// CSV must use double quotes to represent a quote inside a quoted cell
// Quotes must be paired up
// Test if a comma lays outside a pair of quotes. If so, replace the comma with an obscure unicode character
if (Math.Round(Math.Round((decimal) i/2)*2) == i)
{
var s = quotesArray[i].Trim();
switch (s)
{
case ",":
quotesArray[i] = obscureCharacter; // Change quoted comma seperated string to quoted "obscure character" seperated string
break;
}
}
// Build string and Replace quotes where quotes were expected.
unicodeSeparatedString += (i > 0 ? "\"" : "") + quotesArray[i].Trim();
}
}
else
{
// String does not have any pairs of double quotes. It should be safe to just replace the commas with the obscure character
unicodeSeparatedString = csvrow.Replace(",", obscureCharacter);
}
var csvRowArray = unicodeSeparatedString.Split(obscureCharacter[0]);
for (var i = 0; i < csvRowArray.Length; i++)
{
var s = csvRowArray[i].Trim();
if (s.StartsWith("\"") && s.EndsWith("\""))
{
csvRowArray[i] = s.Length > 2 ? s.Substring(1, s.Length - 2) : ""; // Remove start and end quotes.
}
}
return csvRowArray;
}
Ein Nachteil meines Ansatzes ist die Art und Weise, wie ich Trennzeichen vorübergehend durch ein obskures Unicode-Zeichen ersetze. Dieses Zeichen muss so dunkel sein, dass es niemals in Ihrer CSV-Datei angezeigt wird. Möglicherweise möchten Sie dies besser behandeln.