web-dev-qa-db-fra.com

Lire un fichier texte et analyser des lignes en mots en C

Je suis débutant en programmation C et système. Pour un devoir, je dois écrire un programme qui lit en mots l'entrée des lignes d'analyse syntaxique et envoie des mots aux sous-processus de tri à l'aide de files d'attente de messages System V (par exemple, mots de compte). Je me suis retrouvé coincé à l'entrée. J'essaie de traiter les entrées, de supprimer les caractères non-alpha, de mettre tous les mots alpha en minuscule et enfin de scinder une ligne de mots en plusieurs mots. Jusqu'à présent, je peux imprimer tous les mots alpha en minuscule, mais il y a des lignes entre les mots, ce qui, à mon avis, n'est pas correct. Quelqu'un peut-il jeter un coup d'œil et me donner des suggestions? 

Exemple tiré d'un fichier texte: Le projet Gutenberg EBook de L'Iliade d'Homère, d'Homère

Je pense que la sortie correcte devrait être:

the
project
gutenberg
ebook
of
the
iliad
of
homer
by
homer

Mais ma sortie est la suivante:

project
gutenberg
ebook
of
the
iliad
of
homer
                         <------There is a line there
by
homer

Je pense que la ligne vide est causée par l'espace entre "," et "par". J'ai essayé des choses comme "if isspace (c) alors ne fais rien", mais cela ne fonctionne pas. Mon code est ci-dessous. Toute aide ou suggestion est appréciée.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>


//Main Function
int main (int argc, char **argv)
{
    int c;
    char *input = argv[1];
    FILE *input_file;

    input_file = fopen(input, "r");

    if (input_file == 0)
    {
        //fopen returns 0, the NULL pointer, on failure
        perror("Canot open input file\n");
        exit(-1);
    }
    else
    {        
        while ((c =fgetc(input_file)) != EOF )
        {
            //if it's an alpha, convert it to lower case
            if (isalpha(c))
            {
                c = tolower(c);
                putchar(c);
            }
            else if (isspace(c))
            {
                ;   //do nothing
            }
            else
            {
                c = '\n';
                putchar(c);
            }
        }
    }

    fclose(input_file);

    printf("\n");

    return 0;
}

MODIFIER **

J'ai édité mon code et j'ai finalement obtenu le bon résultat:

int main (int argc, char **argv)
{
    int c;
    char *input = argv[1];
    FILE *input_file;

    input_file = fopen(input, "r");

    if (input_file == 0)
    {
        //fopen returns 0, the NULL pointer, on failure
        perror("Canot open input file\n");
        exit(-1);
    }
    else
    {
        int found_Word = 0;

        while ((c =fgetc(input_file)) != EOF )
        {
            //if it's an alpha, convert it to lower case
            if (isalpha(c))
            {
                found_Word = 1;
                c = tolower(c);
                putchar(c);
            }
            else {
                if (found_Word) {
                    putchar('\n');
                    found_Word=0;
                }
            }

        }
    }

    fclose(input_file);

    printf("\n");

    return 0;
}
11
user2203774

Je pense qu'il suffit d'ignorer tout caractère non alpha! Isalpha (c) sinon convertissez-le en minuscule. Vous devrez garder une trace lorsque vous trouverez un mot dans ce cas.

int found_Word = 0;

while ((c =fgetc(input_file)) != EOF )
{
    if (!isalpha(c))
    {
        if (found_Word) {
            putchar('\n');
            found_Word = 0;
        }
    }
    else {
        found_Word = 1;
        c = tolower(c);
        putchar(c);
    }
}

Si vous devez gérer des apostrophes dans des mots tels que "n'est pas", vous devriez le faire.

int found_Word = 0;
int found_apostrophe = 0;
    while ((c =fgetc(input_file)) != EOF )
    {
    if (!isalpha(c))
    {
        if (found_Word) {
            if (!found_apostrophe && c=='\'') {
                found_apostrophe = 1;
            }
            else {
                found_apostrophe = 0;
                putchar('\n');
                found_Word = 0;
            }
                }
    }
    else {
        if (found_apostrophe) {
            putchar('\'');
            found_apostrophe == 0;
        }
        found_Word = 1;
        c = tolower(c);
        putchar(c);
    }
}
6
Rob

Je suppose que vous voulez vraiment gérer tous les caractères non alphabétiques comme séparateurs, et pas seulement les espaces comme séparateurs et ignorer les caractères non alphabétiques. Sinon, foo--bar apparaîtrait sous la forme d'un seul mot foobar, n'est-ce pas? La bonne nouvelle est que cela facilite les choses. Vous pouvez supprimer la clause isspace et utiliser simplement la clause else.

En attendant, que vous traitiez les ponctuations spécialement ou non, vous avez un problème: vous imprimez une nouvelle ligne pour n'importe quel espace. Ainsi, une ligne qui se termine par \r\n ou \n, ou même une phrase se terminant par ., affichera une ligne vierge. La solution évidente consiste à garder trace du dernier caractère, ou d'un drapeau, pour ne pouvoir imprimer une nouvelle ligne que si vous avez déjà imprimé une lettre.

Par exemple:

int last_c = 0

while ((c = fgetc(input_file)) != EOF )
{
    //if it's an alpha, convert it to lower case
    if (isalpha(c))
    {
        c = tolower(c);
        putchar(c);
    }
    else if (isalpha(last_c))
    {
        putchar(c);
    }
    last_c = c;
}

Mais voulez-vous vraiment traiter la ponctuation de la même manière? L'énoncé du problème implique que vous le faites, mais dans la vraie vie, c'est un peu étrange. Par exemple, foo--bar devrait probablement apparaître en tant que mots séparés foo et bar, mais it's devrait-il réellement apparaître en tant que mots séparés it et s? Par ailleurs, utiliser isalpha comme règle pour "Caractères Word" signifie également que, par exemple, 2nd apparaîtra sous la forme nd.

Ainsi, si isascii n'est pas la règle appropriée à votre cas d'utilisation pour distinguer les caractères Word des séparateurs, vous devrez écrire votre propre fonction qui fait la distinction. Vous pouvez facilement exprimer une telle règle en logique (par exemple, isalnum(c) || c == '\'') ou avec une table (juste un tableau de 128 ints, de sorte que la fonction est c >= 0 && c < 128 && Word_char_table[c]). Cette façon de faire présente l’avantage supplémentaire que vous pouvez étendre ultérieurement votre code pour qu’il traite avec Latin-1 ou Unicode, ou pour gérer le texte du programme (qui comporte des caractères Word différents du texte anglais), ou…

1
abarnert

Il semble que vous sépariez les mots par des espaces, alors je pense que

while ((c =fgetc(input_file)) != EOF )
{
    if (isalpha(c))
    {
        c = tolower(c);
        putchar(c);
    }
    else if (isspace(c))
    {
       putchar('\n');
    }
}

va travailler aussi. Pourvu que votre texte d'entrée n'ait pas plus d'un espace entre les mots.

0
P0W