Donné
2,1016,7/31/2008 14: 22, Geoff Dalgas, 6/5/2011 22:21, http://stackoverflow.com , "Corvallis, OR", 7679,351, 81, b437f461b3fd27387c5d8ab47a293d35,34
Comment utiliser C # pour fractionner les informations ci-dessus en chaînes comme suit:
2
1016
7/31/2008 14:22
Geoff Dalgas
6/5/2011 22:21
http://stackoverflow.com
Corvallis, OR
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34
Comme vous pouvez le voir, l’une des colonnes contient <= (Corvallis, OR)
// mettre à jour // basé sur C # Regex Split - virgules en dehors des guillemets
string[] result = Regex.Split(samplestring, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
Utilisez le Microsoft.VisualBasic.FileIO.TextFieldParser
classe. Cela gérera l’analyse d’un fichier délimité, TextReader
ou Stream
où certains champs sont entre guillemets et d’autres pas.
Par exemple:
using Microsoft.VisualBasic.FileIO;
string csv = "2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,\"Corvallis, OR\",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";
TextFieldParser parser = new TextFieldParser(new StringReader(csv));
// You can also read from a file
// TextFieldParser parser = new TextFieldParser("mycsvfile.csv");
parser.HasFieldsEnclosedInQuotes = true;
parser.SetDelimiters(",");
string[] fields;
while (!parser.EndOfData)
{
fields = parser.ReadFields();
foreach (string field in fields)
{
Console.WriteLine(field);
}
}
parser.Close();
Cela devrait générer le résultat suivant:
2 1016 31/07/2008 14:22 Geoff Dalgas 6/5/2011 22:21 http://stackoverflow.com Corvallis, OU 7679 351 81 b437f461b3f327d7ab5a847a293d35 34
Voir Microsoft.VisualBasic.FileIO.TextFieldParser pour plus d'informations.
Vous devez ajouter une référence à Microsoft.VisualBasic
dans l'onglet Ajouter des références .NET.
Il est trop tard, mais cela peut être utile pour quelqu'un. Nous pouvons utiliser RegEx comme ci-dessous.
Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
String[] Fields = CSVParser.Split(Test);
Vous pouvez séparer toutes les virgules suivies d'un nombre pair de guillemets.
Vous voudriez aussi voir au specf
pour le format CSV sur le traitement des virgules.
Lien utile: C# Regex Split - commas outside quotes
Je vois que si vous collez du texte délimité par csv dans Excel et effectuez un "Texte en colonnes", il vous demande un "qualificateur de texte". Par défaut, il utilise une citation double pour traiter le texte entre guillemets comme étant littéral. J'imagine qu'Excel l'implémente en exécutant un caractère à la fois. S'il rencontre un "qualificatif de texte", il continue à passer au "qualificatif" suivant. Vous pouvez probablement l'implémenter vous-même avec une boucle for et un booléen pour indiquer si vous êtes dans un texte littéral.
public string[] CsvParser(string csvText)
{
List<string> tokens = new List<string>();
int last = -1;
int current = 0;
bool inText = false;
while(current < csvText.Length)
{
switch(csvText[current])
{
case '"':
inText = !inText; break;
case ',':
if (!inText)
{
tokens.Add(csvText.Substring(last + 1, (current - last)).Trim(' ', ','));
last = current;
}
break;
default:
break;
}
current++;
}
if (last != csvText.Length - 1)
{
tokens.Add(csvText.Substring(last+1).Trim());
}
return tokens.ToArray();
}
Utilisez une bibliothèque telle que LumenWorks pour lire votre fichier CSV. Il gérera les champs contenant des guillemets et sera globalement plus robuste que votre solution personnalisée du fait de son existence depuis longtemps.
Il est délicat d'analyser les fichiers .csv lorsque le fichier .csv peut être une chaîne séparée par des virgules, une chaîne séparée par des virgules ou une combinaison chaotique des deux. La solution que j'ai proposée ne permet aucune des trois possibilités.
J'ai créé une méthode, ParseCsvRow (), qui renvoie un tableau à partir d'une chaîne csv. Je traite d’abord avec les guillemets doubles dans la chaîne en scindant la chaîne sur des guillemets doubles dans un tableau appelé quotesArray. Les fichiers .csv de chaînes entre guillemets ne sont valides que s’il existe un nombre pair de guillemets doubles. Les guillemets doubles dans une valeur de colonne doivent être remplacés par une paire de guillemets doubles (c'est l'approche d'Excel). Tant que le fichier .csv répond à ces exigences, vous pouvez vous attendre à ce que les virgules de délimitation apparaissent uniquement en dehors des paires de guillemets doubles. Les virgules à l'intérieur de paires de guillemets font partie de la valeur de la colonne et doivent être ignorées lors de la scission du fichier .csv dans un tableau.
Ma méthode testera les virgules en dehors des paires de guillemets en regardant uniquement les index pairs de quotesArray. Il supprime également les guillemets des valeurs de début et de fin de colonne.
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;
}
Un des inconvénients de mon approche est la façon dont je remplace temporairement les virgules séparateurs par un caractère unicode obscur. Ce personnage doit être si obscur qu'il ne figurerait jamais dans votre fichier .csv. Vous voudrez peut-être vous en occuper davantage.
J'ai eu un problème avec un fichier CSV contenant des champs avec un caractère de citation, alors, en utilisant TextFieldParser, j'ai trouvé ce qui suit:
private static string[] parseCSVLine(string csvLine)
{
using (TextFieldParser TFP = new TextFieldParser(new MemoryStream(Encoding.UTF8.GetBytes(csvLine))))
{
TFP.HasFieldsEnclosedInQuotes = true;
TFP.SetDelimiters(",");
try
{
return TFP.ReadFields();
}
catch (MalformedLineException)
{
StringBuilder m_sbLine = new StringBuilder();
for (int i = 0; i < TFP.ErrorLine.Length; i++)
{
if (i > 0 && TFP.ErrorLine[i]== '"' &&(TFP.ErrorLine[i + 1] != ',' && TFP.ErrorLine[i - 1] != ','))
m_sbLine.Append("\"\"");
else
m_sbLine.Append(TFP.ErrorLine[i]);
}
return parseCSVLine(m_sbLine.ToString());
}
}
}
StreamReader est toujours utilisé pour lire le fichier CSV ligne par ligne, comme suit:
using(StreamReader SR = new StreamReader(FileName))
{
while (SR.Peek() >-1)
myStringArray = parseCSVLine(SR.ReadLine());
}
Avec Cinchoo ETL - une bibliothèque open source, elle peut gérer automatiquement les valeurs de colonnes contenant des séparateurs.
string csv = @"2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,""Corvallis, OR"",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";
using (var p = ChoCSVReader.LoadText(csv)
)
{
Console.WriteLine(p.Dump());
}
Sortie:
Key: Column1 [Type: String]
Value: 2
Key: Column2 [Type: String]
Value: 1016
Key: Column3 [Type: String]
Value: 7/31/2008 14:22
Key: Column4 [Type: String]
Value: Geoff Dalgas
Key: Column5 [Type: String]
Value: 6/5/2011 22:21
Key: Column6 [Type: String]
Value: http://stackoverflow.com
Key: Column7 [Type: String]
Value: Corvallis, OR
Key: Column8 [Type: String]
Value: 7679
Key: Column9 [Type: String]
Value: 351
Key: Column10 [Type: String]
Value: 81
Key: Column11 [Type: String]
Value: b437f461b3fd27387c5d8ab47a293d35
Key: Column12 [Type: String]
Value: 34
Pour plus d'informations, veuillez consulter l'article codeproject.
J'espère que ça aide.