Comment gérer les sauts de ligne dans un fichier CSV en utilisant C#?
j'ai une feuille de calcul Excel convertie en fichier CSV en C#, mais j'ai un problème avec les sauts de ligne. Par exemple:
"John","23","555-5555"
"Peter","24","555-5
555"
"Mary,"21","555-5555"
quand je lis le fichier CSV, si l'enregistrement ne commence pas par une double citation (") alors un saut de ligne est là par erreur et je dois le supprimer. J'ai quelques cours de lecture CSV sur internet, mais je crains qu'ils ne échouent sur la ligne de rupture.
Comment dois-je traiter ces lignes les pauses?
Merci beaucoup à tous pour votre aide.
heres est ce que j'ai fait jusqu'à présent, mes dossiers ont format fixe et commencent toutes par
JTW;...;....;...;
JTW;...;...;....
JTW;....;...;..
..;...;... (wrong record, line brak inserted)
JTW;...;...
donc j'ai vérifié pour le ;
dans la position [3] de chaque ligne. si c'est vrai j'écris, si faux malade ajouter sur le dernier *la suppression du saut de ligne)
J'ai des problèmes maintenant parce que j'enregistre le fichier en txt.
soit dit en passant, je suis en train de convertir l'excell spreadshit en csv en enregistrant comme csv dans excell. mais je ne suis pas sûr que le client le fasse.
donc le fichier en TXT est parfait. j'ai vérifié les dossiers et les totaux. Mais maintenant, j'ai à convertir csv et je tiens vraiment à le faire dans le programme. Quelqu'un sait comment faire ?
voici mon code:
namespace EditorCSV
{
class Program
{
static void Main(string[] args)
{
ReadFromFile("c:source.csv");
}
static void ReadFromFile(string filename)
{
StreamReader SR;
StreamWriter SW;
SW = File.CreateText("c:target.csv");
string S;
char C='a';
int i=0;
SR=File.OpenText(filename);
S=SR.ReadLine();
SW.Write(S);
S = SR.ReadLine();
while(S!=null)
{
try { C = S[3]; }
catch (IndexOutOfRangeException exception){
bool t = false;
while (t == false)
{
t = true;
S = SR.ReadLine();
try { C = S[3]; }
catch (IndexOutOfRangeException ex) { S = SR.ReadLine(); t = false; }
}
}
if( C.Equals(';'))
{
SW.Write("rn" + S);
i = i + 1;
}
else
{
SW.Write(S);
}
S=SR.ReadLine();
}
SR.Close();
SW.Close();
Console.WriteLine("Records Processed: " + i.ToString() + " .");
Console.WriteLine("File Created SucacessFully");
Console.ReadKey();
}
}
}
13 réponses
CSV a des façons prédéfinies de gérer cela. Ce site fournit une explication facile à lire de la norme façon de gérer toutes les mises en garde de CSV.
néanmoins, il n'y a vraiment aucune raison de ne pas utiliser une bibliothèque libre solide pour lire et écrire des fichiers CSV pour éviter de faire des erreurs non standard. LINQtoCSV est ma bibliothèque préférée pour cela. Il soutient la lecture et l'écriture d'une manière propre et simple.
alternativement, ce DONC, la question sur CSV bibliothèques va vous donner la liste des choix les plus populaires.
plutôt que de vérifier si la ligne courante manque le (") comme premier caractère, Vérifiez plutôt si le dernier caractère est un ("). Si ce n'est pas le cas, vous savez que vous avez une rupture de ligne, et vous pouvez lire la ligne suivante et la fusionner.
je présume que les données de votre exemple étaient exactes - les champs étaient entourés de guillemets. Si les guillemets ne délimitent pas un champ de texte (ou si les nouvelles lignes se trouvent en quelque sorte dans des données non textuelles), alors tous les paris sont désactivés!
Il existe une méthode intégrée pour lire les fichiers CSV dans .NET (nécessite Microsoft.VisualBasic assemblée référence ajoutée):
public static IEnumerable<string[]> ReadSV(TextReader reader, params string[] separators)
{
var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader);
parser.SetDelimiters(separators);
while (!parser.EndOfData)
yield return parser.ReadFields();
}
Si vous faites affaire avec vraiment de grands fichiers CSV reader prétend être le plus rapide, vous trouverez: http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader
j'ai utilisé ce morceau de code récemment pour analyser les lignes d'un fichier CSV (c'est une version simplifiée):
private void Parse(TextReader reader)
{
var row = new List<string>();
var isStringBlock = false;
var sb = new StringBuilder();
long charIndex = 0;
int currentLineCount = 0;
while (reader.Peek() != -1)
{
charIndex++;
char c = (char)reader.Read();
if (c == '"')
isStringBlock = !isStringBlock;
if (c == separator && !isStringBlock) //end of word
{
row.Add(sb.ToString().Trim()); //add word
sb.Length = 0;
}
else if (c == '\n' && !isStringBlock) //end of line
{
row.Add(sb.ToString().Trim()); //add last word in line
sb.Length = 0;
//DO SOMETHING WITH row HERE!
currentLineCount++;
row = new List<string>();
}
else
{
if (c != '"' && c != '\r') sb.Append(c == '\n' ? ' ' : c);
}
}
row.Add(sb.ToString().Trim()); //add last word
//DO SOMETHING WITH LAST row HERE!
}
peut-être Pouvez-vous compter pour (") pendant le ReadLine(). S'ils sont bizarres, ça hissera le drapeau. Vous pouvez soit ignorer ces lignes, soit obtenir les deux suivantes et éliminer la première occurrence "\n" des lignes de fusion.
ce que je fais habituellement est de lire le texte en caractère par caractère par opposition à ligne par ligne, en raison de ce problème même.
comme vous lisez chaque caractère, vous devriez être en mesure de comprendre où chaque cellule commence et s'arrête, mais aussi la différence entre un linebreak dans une rangée et dans une cellule: si je me souviens bien, pour les fichiers générés par Excel de toute façon, les lignes commencent avec \r\n, et les nouvelles lignes dans les cellules sont seulement \r.
suivez les conseils des experts et Ne pas rouler vos propres CSV analyseur.
votre première pensée est, " Comment puis-je gérer les nouveaux sauts de ligne?"
votre prochaine pensée est, " j'ai besoin de traiter les virgules à l'intérieur des guillemets."
votre prochaine pensée sera, "oh, merde, j'ai besoin de gérer les citations à l'intérieur des citations. Échappé des citations. Guillemet. Apostrophe..."
c'est un chemin vers la folie. Ne pas écrire votre propre. Trouver une bibliothèque avec une vaste unité une couverture de test qui touche toutes les parties difficiles et qui a traversé l'enfer pour vous. Pour .NET, utilisez le libre FileHelpers bibliothèque.
CsvHelper (une bibliothèque que je tiens à jour). Il ignore les rangées vides. Je crois qu'il y a un drapeau que vous pouvez mettre dans FastCsvReader pour qu'il gère les lignes vides aussi.
Lire la ligne.
Divisé en colonnes(champs).
Si vous avez assez de colonnes attendues pour chaque ligne, puis traiter.
Si ce n'est pas le cas, lisez la ligne suivante et capturez les colonnes restantes jusqu'à ce que vous obteniez ce dont vous avez besoin.
Répéter.
une expression régulière assez simple pourrait être utilisée sur chaque ligne. Quand il correspond, vous traitez chaque champ de la correspondance. Quand il ne trouve pas de correspondance, vous sautez cette ligne.
L'expression régulière pourrait ressembler à quelque chose comme ça.
Match match = Regex.Match(line, @"^(?:,?(?<q>['"](?<field>.*?\k'q')|(?<field>[^,]*))+$");
if (match.Success)
{
foreach (var capture in match.Groups["field"].Captures)
{
string fieldValue = capture.Value;
// Use the value.
}
}
regardez FileHelpers Library Il prend en charge la lecture\writing CSV avec des pauses de ligne ainsi que la lecture\writing to excel
la solution de LINQy:
string csvText = File.ReadAllText("C:\Test.txt");
var query = csvText
.Replace(Environment.NewLine, string.Empty)
.Replace("\"\"", "\",\"").Split(',')
.Select((i, n) => new { i, n }).GroupBy(a => a.n / 3);