2 votes

Comment analyser un CSV avec des guillemets délimitant les champs en C ?

Considérez, ce message :

N,8545,01/02/2011 09:15:01.815,"RASTA OPTSTK 24FEB2011 1,150.00 CE",S,8.80,250,0.00,0

Ce n'est qu'un échantillon. L'idée est que c'est une des lignes d'un fichier csv. Maintenant, si je dois le casser en virgules, alors il y aura un problème avec 1150 chiffres.

La chaîne de caractères entre les guillemets est de longueur variable, mais peut être considérée comme un "élément" (si je peux utiliser ce terme). Les autres éléments sont ceux qui sont séparés par ,

Comment puis-je l'analyser ? (autre que le moteur d'analyse de Ragel)

Soham

4voto

Edwin Buck Points 33097

Décomposer la chaîne de caractères en champs séparés par des virgules fourni par que les virgules ne sont pas intégrées dans des chaînes de caractères entre guillemets.

Un moyen rapide de le faire est d'utiliser une machine à états.

boolean inQuote = false;
StringBuffer buffer= new StringBuffer();
// readchar() is to be implemented however you read a char
while ((char = readchar()) != -1) {
  switch (char) {

    case ',':
      if (inQuote == false) {
         // store the field in our parsedLine object for later processing.
         parsedLine.addField(buffer.toString());
         buffer.setLength(0);
      }
      break;

    case '"': 
      inQuote = !inQuote;
      // fall through to next target is deliberate.

    default:
      buffer.append(char);

  }
}

Notez que, bien qu'il s'agisse d'un exemple, les fichiers CSV comportent d'autres éléments qui doivent être pris en compte (comme les guillemets intégrés dans les guillemets, ou la nécessité de supprimer les guillemets extérieurs dans votre exemple).

1voto

CAFxX Points 3911

Une solution simple et rapide si vous ne voulez pas ajouter de bibliothèques externes serait de convertir les guillemets en \0 (le marqueur de fin de chaîne), puis analyse les trois chaînes séparément en utilisant sscanf. C'est laid mais ça devrait fonctionner.

En supposant que l'entrée est bien formée (sinon vous devrez ajouter un traitement des erreurs) :

for (i=0; str[i]; i++)
  if (str[i] == '"') str[i] = 0;
str += sscanf(str, "%c,%d,%d/%d/%d %d:%d:%d.%d,", &var1, &var2, ..., &var9);
var10 = str; // it may be str+1, I don't remember if sscanf consumes also the \0
sscanf(str+strlen(var10), ",%c,%f,%d,%f,%d", &var11, &var12, ..., &var15);

Vous devrez évidemment faire une copie de var10 si vous voulez libérer str immédiatement.

1voto

caf Points 114951

Il s'agit d'une fonction permettant d'obtenir le prochain champ CSV unique à partir d'un fichier d'entrée fourni sous la forme d'un fichier de type FILE * . Il s'attend à ce que le fichier soit ouvert en mode texte, et supporte les champs entre guillemets avec des guillemets intégrés et des nouvelles lignes. Les champs plus longs que la taille du tampon fourni sont tronqués.

int get_csv_field(FILE *f, char *buf, size_t size)
{
    char *p = buf;
    int c;
    enum { QS_UNQUOTED, QS_QUOTED, QS_GOTQUOTE } quotestate = QS_UNQUOTED;

    if (size < 1)
        return EOF;

    while ((c = getc(f)) != EOF)
    {
        if ((c == '\n' || c == ',') && quotestate != QS_QUOTED)
            break;

        if (c == '"')
        {
            if (quotestate == QS_UNQUOTED)
            {
                quotestate = QS_QUOTED;
                continue;
            }

            if (quotestate == QS_QUOTED)
            {
                quotestate = QS_GOTQUOTE;
                continue;
            }

            if (quotestate == QS_GOTQUOTE)
            {
                quotestate = QS_QUOTED;
            }
        }

        if (quotestate == QS_GOTQUOTE)
        {
            quotestate = QS_UNQUOTED;
        }

        if (size > 1)
        {
            *p++ = c;
            size--;
        }
    }

    *p = '\0';

    return c;
}

0voto

John Zwinck Points 43636

Et si libcsv de notre propre Robert Gamble ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X