2009-09-27 8 views
6

Quelqu'un at-il obtenu quelque chose sur la lecture d'un nombre séquentiel à partir du fichier texte par ligne et l'analyse d'un tableau dans C?comment tokenize chaîne à tableau de int dans c?

Ce que j'ai dans un fichier:

12 3 45 6 7 8 
3 5 6 7 
7 0 -1 4 5 

Ce que je veux dans mon programme:

array1[] = {12, 3, 45, 6, 7, 8}; 
array2[] = {3, 5, 6, 7}; 
array3[] = {7, 0, -1, 4, 5}; 

Je suis passé par plusieurs façons de lire, mais la seule question est que lorsque je veux le marquer par ligne. Merci.

+0

merci pour tous, mais maintenant je me rends compte que le problème est de tokenize. –

Répondre

10

Le code suivant lire un fichier d'une ligne à la fois

char line[80] 
FILE* fp = fopen("data.txt","r"); 
while(fgets(line,1,fp) != null) 
{ 
    // do something 
} 
fclose(fp); 

Vous pouvez ensuite tokenise l'entrée en utilisant strtok() et sscanf() pour convertir le texte en nombres.

A partir de la page MSDN pour sscanf:

Chacune de ces fonctions [sscanf et swscanf] renvoie le nombre de champs avec succès convertis et attribués; la valeur de retour n'inclut pas les champs lus mais non affectés. Une valeur de retour de 0 indique qu'aucun champ n'a été affecté. La valeur de retour est EOF pour une erreur ou si la fin de la chaîne est atteinte avant la première conversion .

Le code suivant convertira la chaîne en un tableau d'entiers. Évidemment, pour un tableau de longueur variable, vous aurez besoin d'une liste ou d'une analyse de l'entrée deux fois pour déterminer la longueur du tableau avant de l'analyser.

char tokenstring[] = "12 23 3 4 5"; 
char seps[] = " "; 
char* token; 
int var; 
int input[5]; 
int i = 0; 

token = strtok (tokenstring, seps); 
while (token != NULL) 
{ 
    sscanf (token, "%d", &var); 
    input[i++] = var; 

    token = strtok (NULL, seps); 
} 

Mettant:

char seps[] = " ,\t\n"; 

permettra l'entrée d'être plus flexible.

je devais faire une recherche pour me rappeler la syntaxe - je l'ai trouvé here in the MSDN

+0

pourriez-vous me montrer comment utiliser sscanf() pour un nombre inconnu de nombres par ligne afin de l'analyser en un tableau? –

+0

@ChrisF l'idée que j'ai trouvé ici est d'utiliser int var pour un usage temporaire, btw, merci beaucoup. –

+0

@ChrisF est-il un moyen d'obtenir ceci pour gérer 1,2,, 4? – cokedude

2

Ce que je voudrais faire est de faire une fonction comme ceci:

size_t read_em(FILE *f, int **a); 

Dans la fonction, allouer de la mémoire au pointeur *a, puis commencer à lire les numéros à partir du f et les stocker dans *a. Lorsque vous rencontrez un caractère de nouvelle ligne, il suffit de renvoyer le nombre d'éléments que vous avez stockés dans *a. Ensuite, appelez comme ceci:

int *a = NULL; 
FILE *f = fopen("Somefile.txt", "r"); 
size_t len = read_em(f, &a); 
// now a is an array, and len is the number of elements in that array 

Fonctions utiles:

  • malloc() à allouer un tableau.
  • realloc() pour étendre une matrice ed malloc()
  • fgets() lire une ligne de texte (ou autant que peuvent être stockés).
  • sscanf() pour lire les données d'une chaîne (par exemple une chaîne retournée par fgets()) dans d'autres variables (comme un tableau int créé par malloc() - hint hint)
0

Votre fichier a un certain nombre de lignes ou avez-vous besoin de pouvoir lire un nombre arbitraire dans des tableaux aléatoires?

Voici le code à lire dans un fichier ligne par ligne.

#include <stdio.h> 

int main() 
{ 
    char *inname = "test.txt"; 
    FILE *infile; 
    char line_buffer[BUFSIZ]; 

    infile = fopen(inname, "r"); 
    if (!infile) { 
     printf("Couldn't open file %s for reading.\n", inname); 
     return 0; 
    } 

    while (fgets(line_buffer, sizeof(line_buffer), infile)) { 
     // process line 
    } 

    return 0; 
} 

Vous pouvez utiliser sscanf ou tout d'un certain nombre de tokenizing/conversion des fonctions pour extraire les nombres. BUFSIZ est une bonne constante de stdio.h conçue pour rendre les E/S de flux efficaces sur un système cible.

+0

Pourquoi gardez-vous un 'line_number' comme type' char'? Voulez-vous être limité à 127 lignes? –

+0

pourriez-vous me montrer comment extraire les nombres en utilisant sscanf? –

+0

line_number ne devrait même pas être là, c'est un artefact d'un autre code ... supprimé maintenant. – phoebus

2

Je vous suggère fortement de ne PAS utiliser sscanf et vos amis lorsque le nombre de champs est variable. Utiliser strtok et atoi. Assurez-vous de bien lire la page de manuel strtok, de nombreux programmeurs que je connais trouvent sa syntaxe un peu surprenante au début. Notez également que strtok va modifier la chaîne d'entrée, donc vous voudrez peut-être travailler sur une copie.

+1

mieux encore: utilisez 'strtol()' de sorte que vous n'aurez pas besoin de 'strtok()' – Christoph

1

Le code suivant peut être ce que vous cherchez. J'espère que vous n'aurez pas besoin d'une description trop détaillée, mais si vous avez des questions, n'hésitez pas à demander.

Il utilise essentiellement une boucle fgets pour lire chaque ligne et strtok pour séparer cette ligne en champs. Il construit une liste chaînée de tableaux entiers qui contiennent les données réelles - vous pouvez voir l'utilisation de cette liste liée dans le code à la fin qui vide la table.

Il a également un moyen par lequel il peut gérer des lignes de taille arbitraire dans le fichier d'entrée sans débordement de tampon (sous réserve de contraintes de mémoire bien sûr). Gardez à l'esprit que le strtok attend seulement un espace entre chaque champ sur la ligne bien que puisse être recodé pour gérer plusieurs espaces ou même toute quantité d'espace blanc. J'ai gardé ce peu simple puisque le code devenait déjà un peu gros :-)

La fonction atoi permet de convertir le mot individuel sur chaque ligne en entiers. Si vous voulez vérifier les erreurs, j'appellerais votre propre variante qui vérifie également que tous les caractères du mot sont numériques.

Utilisation de votre fichier d'entrée:

12 3 45 6 7 8 
3 5 6 7 
7 0 -1 4 5 

il produit une sortie le long des lignes de:

0x97b5170, size = 6: 
    12 3 45 6 7 8 
0x97b51d0, size = 4: 
    3 5 6 7 
0x97b51e0, size = 5: 
    7 0 -1 4 5 

Voici le code qui a produit cette sortie:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <errno.h> 

// This is the linked list of integer arrays. 

typedef struct _tIntArray { 
    int size; 
    int *array; 
    struct _tIntArray *next; 
} tIntArray; 
static tIntArray *first = NULL; 
static tIntArray *last = NULL; 

// Add a line of integers as a node. 

static int addNode (char *str) { 
    tIntArray *curr; // pointers for new integer array. 
    char *word;  // word within string. 
    char *tmpStr;  // temp copy of buffer. 
    int fldCnt;  // field count for line. 
    int i; 

    // Count number of fields. 

    if ((tmpStr = strdup (str)) == NULL) { 
     printf ("Cannot allocate duplicate string (%d).\n", errno); 
     return 1; 
    } 
    fldCnt = 0; 
    for (word = strtok (tmpStr, " "); word; word = strtok (NULL, " ")) 
     fldCnt++; 
    free (tmpStr); 

 

// Create new linked list node. 

    if ((curr = malloc (sizeof (tIntArray))) == NULL) { 
     printf ("Cannot allocate integer array node (%d).\n", errno); 
     return 1; 
    } 

    curr->size = fldCnt; 
    if ((curr->array = malloc (fldCnt * sizeof (int))) == NULL) { 
     printf ("Cannot allocate integer array (%d).\n", errno); 
     free (curr); 
     return 1; 
    } 
    curr->next = NULL; 

    for (i = 0, word = strtok (str, " "); word; word = strtok (NULL, " ")) 
     curr->array[i++] = atoi (word); 

    if (last == NULL) 
     first = last = curr; 
    else { 
     last->next = curr; 
     last = curr; 
    } 

    return 0; 
} 

 

int main(void) { 
    int lineSz;  // current line size. 
    char *buff;  // buffer to hold line. 
    FILE *fin;  // input file handle. 
    long offset;  // offset for re-allocating line buffer. 
    tIntArray *curr; // pointers for new integer array. 
    int i; 

    // Open file. 

    if ((fin = fopen ("qq.in", "r")) == NULL) { 
     printf ("Cannot open qq.in, errno = %d\n", errno); 
     return 1; 
    } 

    // Allocate initial line. 

    lineSz = 2; 
    if ((buff = malloc (lineSz+1)) == NULL) { 
     printf ("Cannot allocate initial memory, errno = %d.\n", errno); 
     return 1; 
    } 

    // Loop forever. 

    while (1) { 
     // Save offset in case we need to re-read. 

     offset = ftell (fin); 

 

 // Get line, exit if end of file. 

     if (fgets (buff, lineSz, fin) == NULL) 
      break; 

     // If no newline, assume buffer wasn't big enough. 

     if (buff[strlen(buff)-1] != '\n') { 
      // Get bigger buffer and seek back to line start and retry. 

      free (buff); 
      lineSz += 3; 
      if ((buff = malloc (lineSz+1)) == NULL) { 
       printf ("Cannot allocate extra memory, errno = %d.\n", errno); 
       return 1; 
      } 
      if (fseek (fin, offset, SEEK_SET) != 0) { 
       printf ("Cannot seek, errno = %d.\n", errno); 
       return 1; 
      } 
      continue; 
     } 

     // Remove newline and process. 

     buff[strlen(buff)-1] = '\0'; 
     if (addNode (buff) != 0) 
      return 1; 
    } 

 

// Dump table for debugging. 

    for (curr = first; curr != NULL; curr = curr->next) { 
     printf ("%p, size = %d:\n ", curr, curr->size); 
     for (i = 0; i < curr->size; i++) 
      printf (" %d", curr->array[i]); 
     printf ("\n"); 
    } 

    // Free resources and exit. 

    free (buff); 
    fclose (fin); 
    return 0; 
} 
0

Utilisation strtol() pour analyser chaque ligne:

#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    static char buffer[1024]; 
    static long values[256]; 

    while(fgets(buffer, sizeof buffer, stdin)) 
    { 
     char *current = buffer; 
     size_t i = 0; 
     while(*current && *current != '\n' && 
      i < sizeof values/sizeof *values) 
     { 
      char *tail = NULL; 
      errno = 0; 
      values[i] = strtol(current, &tail, 0); 

      if(errno || tail == current) 
      { 
       fprintf(stderr, "failed to parse %s\n", current); 
       break; 
      } 

      ++i, current = tail; 
     } 

     // process values 
     printf("read %i values\n", i); 
    } 
} 
Questions connexes