Citiți dintr-un fișier text și analizați liniile în cuvinte în C (Programare, C, Fișier, Fișier Io, Io)

user2203774 a intrebat.
a intrebat.

Sunt un începător în C și programare de sistem. Pentru o temă de casă, trebuie să scriu un program care citește intrările din stdin, analizând liniile în cuvinte și trimițând cuvintele la subprocesele de sortare folosind cozile de mesaje System V (de exemplu, numără cuvintele). M-am blocat la partea de intrare. Încerc să procesez intrarea, să elimin caracterele non-alfa, să pun toate cuvintele alfa în minuscule și, în cele din urmă, să împart o linie de cuvinte în mai multe cuvinte. Până acum pot imprima toate cuvintele alfa în minuscule, dar există linii între cuvinte, ceea ce cred că nu este corect. Poate cineva să arunce o privire și să-mi dea câteva sugestii?

Exemplu dintr-un fișier text: The Project Gutenberg EBook of The Iliad of Homer, de Homer

Cred că ieșirea corectă ar trebui să fie:

the
project
gutenberg
ebook
of
the
iliad
of
homer
by
homer

Dar rezultatul meu este următorul:

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

Cred că linia goală este cauzată de spațiul dintre „,” și „by”. Am încercat lucruri precum „if isspace(c) then do nothing”, dar nu funcționează. Codul meu este mai jos. Orice ajutor sau sugestie este apreciată.

#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
");
        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 = '
';
                putchar(c);
            }
        }
    }

    fclose(input_file);

    printf("
");

    return 0;
}

EDITARE **

Mi-am editat codul și în sfârșit am obținut ieșirea corectă:

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
");
        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('
');
                    found_word=0;
                }
            }

        }
    }

    fclose(input_file);

    printf("
");

    return 0;
}

Comentarii

  • +1 pentru postarea unui cod rezonabil. O sugestie: perror( input ). Există puține lucruri mai rele decât un mesaj de eroare fără un nume de fișier. –  > Por William Pursell.
  • Funcția strtok poate fi de ajutor . –  > Por keety.
3 răspunsuri
user2601278

Cred că trebuie doar să ignorați orice caracter non-alfa !isalpha(c) în caz contrar, convertiți în minusculă. Va trebui să țineți evidența atunci când găsiți un cuvânt în acest caz.

int found_word = 0;

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

Dacă aveți nevoie să vă ocupați de apostrofuri în cadrul cuvintelor, cum ar fi „nu este”, atunci acest lucru ar trebui să o facă –

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('
');
                found_word = 0;
            }
                }
    }
    else {
        if (found_apostrophe) {
            putchar(''');
            found_apostrophe = 0;
        }
        found_word = 1;
        c = tolower(c);
        putchar(c);
    }
}

abarnert

Bănuiesc că doriți cu adevărat să vă ocupați de toate caracterele non-alfabetice ca și separatori, nu doar spațiile ca și separatori și să ignorați caracterele non-alfabetice. În caz contrar, foo--bar ar apărea ca un singur cuvânt foobar, , corect? Vestea bună este că acest lucru ușurează lucrurile. Puteți elimina isspace și să folosiți doar clauza else clauză.

Între timp, indiferent dacă tratați sau nu punctuațiile în mod special, aveți o problemă: imprimați o linie nouă pentru orice spațiu. Astfel, o linie care se termină cu r
sau
, , sau chiar o propoziție care se termină cu ., , va imprima o linie albă. Soluția evidentă pentru a evita acest lucru este să țineți cont de ultimul caracter sau de un indicator, astfel încât să imprimați o linie nouă numai dacă ați imprimat anterior o literă.

De exemplu:

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;
}

Dar chiar doriți să tratați toate semnele de punctuație în același mod? Enunțul problemei implică faptul că da, dar în viața reală, acest lucru este puțin ciudat. De exemplu, foo--bar ar trebui probabil să apară ca cuvinte separate foo și bar, , dar ar trebui it's într-adevăr să apară ca cuvinte separate it și s? În acest sens, utilizarea isalpha ca regulă pentru „caracterele cuvintelor” înseamnă, de asemenea, că, să zicem, 2nd va apărea ca nd.

Așadar, dacă isascii nu este regula potrivită pentru cazul dumneavoastră de utilizare pentru a distinge caracterele de cuvânt de caracterele de separare, va trebui să vă scrieți propria funcție care să facă distincția corectă. Puteți exprima cu ușurință o astfel de regulă în logică (de ex, isalnum(c) || c == ''') sau cu un tabel (doar o matrice de 128 de ints, astfel încât funcția este c >= 0 && c < 128 && word_char_table[c]). Făcând lucrurile în acest fel, aveți avantajul suplimentar că vă puteți extinde ulterior codul pentru a trata cu Latin-1 sau Unicode, sau pentru a gestiona textul programului (care are caractere de cuvânt diferite de cele ale textului în limba engleză), sau …

Comentarii

  • Rețineți că acest lucru va opri unele semne de punctuație care ar putea fi necesare pentru a fi păstrate, inclusiv cratimele și apostrofele. este posibil să fie nevoie să le scrieți în cazuri speciale, iar în unele cazuri (de exemplu, cratimele urmate de linii noi) să le aruncați oricum. În caz contrar, cuvinte precum „nu este” nu își vor păstra reprezentările originale. –  > Por WhozCraig.
  • @WhozCraig: Da; din moment ce OP a sărit în mod explicit toată punctuația, am ales să fac același lucru. Dar dacă nu asta vrea, are nevoie de un cod suplimentar pentru asta. Voi adăuga o notă despre asta la răspuns. –  > Por abarnert.
  • Problema de a permite isn't este că atunci ar trebui să permită și classes' ca „un singur cuvânt”. Depinde de datele de intrare dacă frazele cu ghilimele simple vor fi următorul problemă, atunci. –  > Por Jongware.
  • @Jongware: Da, nu există un răspuns corect și evident aici; OP trebuie să înțeleagă problema și să își dea seama ce răspuns este potrivit pentru scopurile sale. Având în vedere modul în care a descris problema temei pentru acasă, cred că cel mai simplu răspuns poate fi cel corect. Dar el ar trebui să se gândească bine și să decidă. Așa că WhozCraig a avut dreptate să aducă în discuție acest aspect. –  > Por abarnert.
  • @abarnert: Mulțumesc foarte mult pentru că mi-ați răspuns la întrebare. Da, aveți dreptate. Vreau să tratez toate caracterele non-alfabetice ca separatori. Am folosit sugestia dvs. pentru a-mi corecta codul. Toate literele sunt una lângă alta. Există o modalitate prin care pot împărți un rând de cuvinte în mai multe cuvinte? Voi edita codul meu pentru a vă arăta. Vă mulțumesc din nou. –  > Por user2203774.
P0W

Se pare că separați cuvintele prin spații, așa că eu cred că doar

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

va funcționa de asemenea. Cu condiția ca textul de intrare să nu aibă mai mult de un spațiu între cuvinte.

Comentarii

  • Există o singură virgulă în intrare care nu este copiată în ieșire. Brevatul descrie, de asemenea, „cuvinte”. Cu toate acestea, scurt și simplu; ușor de ajustat. –  > Por Jongware.