Parse une matrice dans un fichier Texte en c

Résolu/Fermé
mok - Modifié le 13 juil. 2022 à 17:48
mamiemando Messages postés 33077 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 18 avril 2024 - 13 juil. 2022 à 17:59

Bonjour,

Je cherche à savoir comment lire en langage C une cellule spécifique dans une matrice, lorsque la matrice est enregistrée dans un fichier texte ou csv.

Par exemple, pour la colonne A et la ligne E, la cellule à lire est 2.

Voila la matrice:

A R N D C Q E G H I L K M F P S T W Y V B Z X
E 2 -2 0 0 -2 0 0 1 -1 -1 -2 -1 -1 -3 1 1 1 -6 -3 0 0 0 0
R -2 6 0 -1 -4 1 -1 -3 2 -2 -3 3 0 -4 0 0 -1 2 -4 -2 -1 0 -1
N 0 0 2 2 -4 1 1 0 2 -2 -3 1 -2 -3 0 1 0 -4 -2 -2 2 1 0
D 0 -1 2 4 -5 2 3 1 1 -2 -4 0 -3 -6 -1 0 0 -7 -4 -2 3 3 -1
C -2 -4 -4 -5 12 -5 -5 -3 -3 -2 -6 -5 -5 -4 -3 0 -2 -8 0 -2 -4 -5 -3
Q 0 1 1 2 -5 4 2 -1 3 -2 -2 1 -1 -5 0 -1 -1 -5 -4 -2 1 3 -1
E 0 -1 1 3 -5 2 4 0 1 -2 -3 0 -2 -5 -1 0 0 -7 -4 -2 3 3 -1
G 1 -3 0 1 -3 -1 0 5 -2 -3 -4 -2 -3 -5 0 1 0 -7 -5 -1 0 0 -1
H -1 2 2 1 -3 3 1 -2 6 -2 -2 0 -2 -2 0 -1 -1 -3 0 -2 1 2 -1
I -1 -2 -2 -2 -2 -2 -2 -3 -2 5 2 -2 2 1 -2 -1 0 -5 -1 4 -2 -2 -1
L -2 -3 -3 -4 -6 -2 -3 -4 -2 2 6 -3 4 2 -3 -3 -2 -2 -1 2 -3 -3 -1
K -1 3 1 0 -5 1 0 -2 0 -2 -3 5 0 -5 -1 0 0 -3 -4 -2 1 0 -1
M -1 0 -2 -3 -5 -1 -2 -3 -2 2 4 0 6 0 -2 -2 -1 -4 -2 2 -2 -2 -1
F -3 -4 -3 -6 -4 -5 -5 -5 -2 1 2 -5 0 9 -5 -3 -3 0 7 -1 -4 -5 -2
P 1 0 0 -1 -3 0 -1 0 0 -2 -3 -1 -2 -5 6 1 0 -6 -5 -1 -1 0 -1
S 1 0 1 0 0 -1 0 1 -1 -1 -3 0 -2 -3 1 2 1 -2 -3 -1 0 0 0
T 1 -1 0 0 -2 -1 0 0 -1 0 -2 0 -1 -3 0 1 3 -5 -3 0 0 -1 0
W -6 2 -4 -7 -8 -5 -7 -7 -3 -5 -2 -3 -4 0 -6 -2 -5 17 0 -6 -5 -6 -4
Y -3 -4 -2 -4 0 -4 -4 -5 0 -1 -1 -4 -2 7 -5 -3 -3 0 10 -2 -3 -4 -2
V 0 -2 -2 -2 -2 -2 -2 -1 -2 4 2 -2 2 -1 -1 -1 0 -6 -2 4 -2 -2 -1
B 0 -1 2 3 -4 1 3 0 1 -2 -3 1 -2 -4 -1 0 0 -5 -3 -2 3 2 -1
Z 0 0 1 3 -5 3 3 0 2 -2 -3 0 -2 -5 0 0 -1 -6 -4 -2 2 3 -1
X 0 -1 0 -1 -3 -1 -1 -1 -1 -1 -1 -1 -1 -2 -1 0 0 -4 -2 -1 -1 -1 -1



Je vous remercie d'avance.

A voir également:

4 réponses

[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 6 juil. 2022 à 14:23
Salut mok,

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
1
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 6 juil. 2022 à 14:42
Je viens de voir que les lettres qui identifient tes colonnes et lignes sont les mêmes, sauf la première ligne. S'il s'agit d'une erreur et qu'en fait c'est la même suite A, R, N, etc. pour les lignes et les colonnes, tu as juste à faire un seul tableau de correspondance pour tes indices.
1
mamiemando Messages postés 33077 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 18 avril 2024 7 748
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

1

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;
}
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
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()

0
Phil_1857 Messages postés 1883 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 178
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)

0