Parse une matrice dans un fichier Texte en c
Résolu/Fermémamiemando Messages postés 33410 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 2 décembre 2024 - 13 juil. 2022 à 17:59
- Parse une matrice dans un fichier Texte en c
- Fichier rar - Guide
- Comment ouvrir un fichier epub ? - Guide
- Comment réduire la taille d'un fichier - Guide
- Ouvrir un fichier .bin - Guide
- Fichier host - Guide
4 réponses
Modifié le 6 juil. 2022 à 14:23
Comme il y a des int répartis en 23 lignes et 23 colonnes, tu peux lire le fichier texte et stocker les données dans un tableau à 2 dimensions de int, par exemple
int tab[23][23];
Ensuite, ta difficulté est que tu veux faire correspondre des lettres majuscules à tes indices de tableaux où sont stockées les données.
Par exemple pour les indices relatifs aux colonnes : A, R, N, etc. à 0, 1, 2, etc.
Pour cela, tu peux utiliser deux autres tableaux à une dimension, cette fois, fonctionnant comme une table de hachage en te servant de la valeur entière du caractère (code ASCII).
Par exemple, en analysant la première ligne, te donnant les correspondances des colonnes, tu vas stocker :
idx_col['A'] = 0; idx_col['R'] = 1; idx_col['N'] = 2;
Tu fais pareil pour les lignes à mesure que tu les analyses, en mettant les index dans un tableau
idx_lig[].
Ensuite, pour accéder à la valeur stockée pour la lettre A en colonne et E en ligne, tu pourras juste faire :
int valeur = tab[ idx_lig['E'] ][ idx_col['A'] ];
Dal
Modifié le 13 juil. 2022 à 21:27
Bonjour,
Est-ce que tu t'autorises le C++ ou tu veux vraiment le faire en C ? Car en C, la manière naturelle de procéder est d'utiliser strtok si tu n'as pas de case vide (voir cette discussion) mais c'est un peu lourd à écrire. En C++, des librairies comme boost permettent d'écrire le parseur beaucoup plus facilement (voir cette discussion).
Coder en C pose d'autres problèmes dans le cas présent (qui se gèrent facilement en C++). Soit tu as un a priori sur le nombre de ligne et de colonnes et tu peux te permettre de faire des allocations statiques (comme proposé par Dal dans le message #1) et ça veut dire que le programme plantera le jour où tu considérera un fichier contenant une matrice impliquant plus de ligne ou plus de colonnes ; soit il faut faire des allocations dynamique et ça rend le programme encore plus compliqué à écrire.
Ensuite ce serait intéressant de voir comment ce fichier texte a été produit. Il y a peut-être une manière plus élégante de transvaser ta matrice en C (par exemple avec un dump).
Pour finir, ce que tu proposes correspond plus ou moins à ce qu'on appelle dans d'autres langage (python notamment) une dataframe. Donc si je devais le coder en C, je ferais une structure de matrice (raisonnant purement sur des index de lignes et de colonnes) puis une structure dataframe qui a pour attribut une matrice et les tableaux permettant de récupérer un index de ligne ou de colonne à partir de la lettre correspondante (et par suite une cellule).
Voici à quoi ça pourrait ressembler :
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct matrix_t { size_t num_rows; size_t num_cols; int ** data; } matrix_t; matrix_t * matrix_create(size_t num_rows, size_t num_cols) { matrix_t * a = malloc(sizeof(matrix_t)); a->num_rows = num_rows; a->num_cols = num_cols; a->data = malloc(num_rows * sizeof(int *)); for (size_t i = 0; i < num_rows; i++) { a->data[i] = calloc(num_cols, sizeof(int)); } return a; } void matrix_free(matrix_t *a) { for (size_t i = 0; i < a->num_rows; i++) { free(a->data[i]); } free(a->data); free(a); } int matrix_get(const matrix_t *a, size_t i, size_t j) { if (i > a->num_rows) { fprintf(stderr, "matrix_get: Invalid i: %zu", i); return 0; } if (j > a->num_cols) { fprintf(stderr, "matrix_get: Invalid j: %zu", j); return 0; } return a->data[i][j]; } void matrix_set(matrix_t * a, size_t i, size_t j, int a_ij) { a->data[i][j] = a_ij; } void matrix_print(const matrix_t *a) { for (size_t i = 0; i < a->num_rows; i++) { for (size_t j = 0; j < a->num_cols; j++) { printf("%d\t", matrix_get(a, i, j)); } printf("\n"); } } typedef struct dataframe_t { matrix_t * matrix; // We assume that columns (resp. rows) are identified by a character between 'A' and 'Z' size_t map_row[26]; size_t map_col[26]; } dataframe_t; void dataframe_print_map(const size_t * map) { for (size_t i = 0; i < 26; i++) { printf("%zu (%c)-> %zu;\n", i, 'A' + i, map[i]); } printf("\n"); } dataframe_t * dataframe_create( matrix_t * matrix, const char *rows, const char *cols ) { dataframe_t * df = malloc(sizeof(dataframe_t)); df->matrix = matrix; for (size_t i = 0; i < 26; i++) { df->map_row[i] = df->map_col[i] = -1; } for (size_t i = 0; i < matrix->num_rows; i++) { size_t row = rows[i] - 'A'; if (!(row < 26)) { fprintf(stderr, "dataframe_create: Invalid rows\n"); return NULL; } if (df->map_row[row] != -1) { fprintf(stderr, "dataframe_create: Colliding row label %c\n", rows[i]); } df->map_row[row] = i; } for (size_t j = 0; j < matrix->num_cols; j++) { size_t col = cols[j] - 'A'; if (!(col < 26)) { fprintf(stderr, "dataframe_create: Invalid cols\n"); return NULL; } if (df->map_col[col] != -1) { fprintf(stderr, "dataframe_create: Colliding col label %c\n", cols[j]); } df->map_col[col] = j; } return df; } void dataframe_free(dataframe_t * df) { matrix_free(df->matrix); } int dataframe_get_from_label(const dataframe_t * df, char row, char col) { size_t i = df->map_row[row - 'A'], j = df->map_col[col - 'A']; if (i > df->matrix->num_rows) { fprintf(stderr, "dataframe_get_from_label: Invalid row: %c", row); return 0; } if (j > df->matrix->num_cols) { fprintf(stderr, "dataframe_get_from_label: Invalid col: %c", col); return 0; } return matrix_get(df->matrix, i, j); } int dataframe_get(const dataframe_t * df, size_t i, size_t j) { return matrix_get(df->matrix, i, j); } dataframe_t * parse_dataframe(FILE * fp, size_t num_rows, size_t num_cols) { char line[1024]; size_t i, j; char *rows = malloc(sizeof(num_rows) * sizeof(char)); char *cols = malloc(sizeof(num_cols) * sizeof(char)); matrix_t * matrix = matrix_create(num_rows, num_cols); for (i = 0; fgets(line, 1024, fp); i++) { const char *tok; for ( j = 0, tok = strtok(line, " "); tok && *tok; tok = strtok(NULL, " \n"), j++ ) { if (i == 0) { // Parsing column headers char c = tok[0]; cols[j] = c; } else { // Parsing following rows if (j == 0) { // Parsing row header char c = tok[0]; rows[i - 1] = c; } else { // Parsing cell int a_ij = atoi(tok); matrix_set(matrix, i - 1, j - 1, a_ij); } } } } dataframe_t * df = dataframe_create(matrix, rows, cols); free(cols); free(rows); return df; } void dataframe_print(const dataframe_t * df) { printf("map_row:\n"); dataframe_print_map(df->map_row); printf("\n"); printf("map_col:\n"); dataframe_print_map(df->map_col); printf("\n"); printf("matrix:\n"); matrix_print(df->matrix); } int main(int argc, char **argv) { const char *filename = "dataframe.csv"; FILE *fp = fopen(filename, "r"); dataframe_t * df; if (fp) { df = parse_dataframe(fp, 23, 23); fclose(fp); } else { fprintf(stderr, "Could not read %s\n", filename); return 1; } if (df) { //dataframe_print(df); char row = 'E', col = 'A'; printf("df[%c,%c] = %d\n", row, col, dataframe_get_from_label(df, row, col)); size_t i = 0, j = 0; printf("df[%zu,%zu] = %d\n", i, j, dataframe_get(df, i, j)); dataframe_free(df); } return 0; }
Bonne chance
Bonjour,
Je te remercie pour ta réponse.
J'ai commencé à appliquer ta solution. La matrice de la première ligne avec les indices est résolue. Par contre, je trouve des difficultés pour la deuxième matrice des entiers où il y a des entiers négatifs. Après l'exécution de la fonction, la matrice "Matrice" est remplie d'entiers qui ne sont pas les mêmes que ceux du fichier.
Merci de m'aider.
Voila mon code.
int** matriceScore(char filepath[20]){ int Matrix[23][23]; FILE *f; int i=0,j=0; char score ; f = fopen(filepath, "r"); if (!f){ printf("\a ERREUR: Impossible d'ouvrir " "le fichier matrice\n");} else{ while(i<23){ do{ while(j<23){ fscanf(f,"%c",&score); if( (!(isalpha(score))) && (!(isblank(score))) ){ if (score=='-'){ fscanf(f,"%c", &score); Matrix[i][j]=-(int)score; j++; }else{ Matrix[i][j]=(int)score; j++; } } } }while(score!=EOF); i++; } } return Matrix; }
Modifié le 7 juil. 2022 à 15:18
Je n'ai pas regardé en détails le code, mais
int Matrix[23][23];
est un tableau local à ta fonction, et il n'existe pas dans le scope de la fonction appelante.
Tu peux, en revanche, déclarer ce tableau dans la fonction appelante et le passer en paramètre à ta fonction.
Tu dois donc modifier le prototype de ta fonction matriceScore()
Modifié le 8 juil. 2022 à 10:25
Bonjour,
Ce serait plus simple de lire les valeurs comme des entiers, avec %d
(lire le 1er caractère de chaque ligne comme un char)
Modifié le 6 juil. 2022 à 14:42