8
votes

Analyser un CSV avec une virgule dans les données

Dupliqué possible: strong>
traiter avec des virgules dans un fichier CSV P>

Je me suis écrit un analyseur CSV Cela fonctionne bien jusqu'à ce que je frappe cet enregistrement: B002VECGTG, B002VECGTG, HAS_17131_SPACESHOOTER, "4 426", 0,04%, "4 832", 0,03%, 0%, 1,0,02%, 20,47 $, 1 code> Les échappés, dans "4,426" et dans "4,426" freinent mon analyseur. P>

C'est ce que j'utilise pour analyser la ligne de texte: P>

            char[] comma = { ',' };
            string[] words = line.Split(comma);


1 commentaires

@ KD7 Cette solution utilise une bibliothèque pour analyser le fichier, ici, j'essaie de le faire avec Split.


3 Réponses :


12
votes

Vous ne pouvez pas simplement vous séparer sur la virgule. Pour mettre en œuvre un analyseur approprié pour cette affaire, vous devez vous mettre en boucle dans la chaîne vous-même, en gardant une trace de si vous êtes à l'intérieur de citations ou non. Si vous êtes à l'intérieur d'une chaîne cité, vous devez continuer jusqu'à ce que vous trouviez une autre citation.

IEnumerable<string> LineSplitter(string line)
{
    int fieldStart = 0;
    for(int i = 0; i < line.Length; i++)
    {
        if(line[i] == ',')
        {    
            yield return line.SubString(fieldStart, i - fieldStart);
            fieldStart = i + 1;
        }
        if(line[i] == '"')
            for(i++; line[i] != '"'; i++) {}
    }
}


4 commentaires

Cette méthode aime couper les mots.


J'ai soumis une modification pour l'erreur hors-tête dans la sous-chaîne et les accolades frisées manquantes sur la seconde en boucle. En outre, cela ne supprima pas les citations des champs cités et a un comportement différent de Split lorsqu'il est appelé ""


Cet exemple tombe le dernier article de la liste.


IEnumerable Lignes Lignesplitter (ligne de cordes) {int FieldStart = 0; pour (int i = 0; i



5
votes

Je suggère d'utiliser un analyseur CSV au lieu d'essayer d'analyser vous-même.

Il y a des nuances à analyser correctement CSV, comme vous l'avez déjà découvert.

Il existe de nombreux tiers (et plusieurs d'entre eux sont gratuits), et même une intégrée à l'espace de noms de base visual - le TextfieldParser dans le Microsoft.visalbasic.fileio Espace de noms.


3 commentaires

+1 pour le TextFieldParser - Pourquoi est-il caché dans l'espace de noms VB?


@Anders - bonne question ... c'est une classe vraiment utile. Cependant, pour les grands fichiers CSV, il est apparemment lent.


Aimez le TextfieldParser ici aussi! Et également pertinent pour cette réponse à l'utilisation d'un utilitaire tiers, consultez la bibliothèque FichierHelPers chez FileHelPers.com (Licences LGPL) pour quelque chose non seulement très facile à utiliser, mais aussi comme un excellent exemple d'étudier et d'apprendre si vous le souhaitez ...



1
votes

Il est possible d'utiliser une regex:

List<List<String>> rows = new List<List<String>>();
MatchCollection matches = Regex.Matches(input, @"^(?:(?:\s*""(?<value>[^""]*)""\s*|(?<value>[^,]*)),)*?(?:\s*""(?>value>[^""]*)""\s*|(?<value>[^,]*))$", RegexOptions.Multiline);
foreach(Match row in matches)
{
    List<String> values = new List<String>();
    foreach(Capture value in row.Groups["value"].Captures)
    {
        values.Add(value.Value);
    }
    rows.Add(values);
}


0 commentaires