12

私は C およびシステム プログラミングの初心者です。宿題のために、stdin 構文解析行からの入力を単語に読み取り、System V メッセージ キューを使用して並べ替えサブプロセスに単語を送信するプログラムを作成する必要があります (単語のカウントなど)。入力部分で引っかかりました。入力を処理し、アルファベット以外の文字を削除し、すべてのアルファベットの単語を小文字にして、最後に単語の行を複数の単語に分割しようとしています。これまでのところ、すべてのアルファベットの単語を小文字で出力できますが、単語間に線があり、正しくないと思います。誰かが見て、私にいくつかの提案をしてもらえますか?

テキスト ファイルの例: The Project Gutenberg EBook of The Iliad of Homer, by Homer

正しい出力は次のようになるはずです。

the
project
gutenberg
ebook
of
the
iliad
of
homer
by
homer

しかし、私の出力は次のとおりです。

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

空行は「,」と「by」の間のスペースが原因だと思います。「if isspace(c)なら何もしない」とかやってみましたがだめでした。私のコードは以下です。任意のヘルプや提案をいただければ幸いです。

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

編集**

コードを編集したところ、最終的に正しい出力が得られました。

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

3 に答える 3

6

アルファベット以外の文字は無視する必要があると思います。それ以外の!isalpha(c)場合は小文字に変換します。この場合、単語を見つけたら追跡する必要があります。

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

「isn't」などの単語内のアポストロフィを処理する必要がある場合は、これで処理できます-

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);
    }
}
于 2013-08-07T17:45:17.523 に答える
1

スペースをセパレータとして処理し、アルファベット以外の文字を無視するだけでなく、アルファベット以外のすべての文字をセパレータとして扱いたいと本当に思っています。そうしfoo--barないと、単一の単語として表示されfoobarますよね?良いニュースは、それが物事をより簡単にすることです。句を削除して、isspace句のみを使用できますelse

一方、句読点を特別に扱うかどうかに関係なく、問題があります。つまり、任意のスペースに対して改行を出力します。そのため、 またはで終わる行、\r\nまたは\nで終わる文でさえ、.空白行が出力されます。これを回避する明白な方法は、最後の文字またはフラグを追跡することです。そのため、以前に文字を印刷したことがある場合にのみ改行を印刷します。

例えば:

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

しかし、本当にすべての句読点を同じように扱いたいですか? 問題文はあなたがそうしていることを暗示していますが、実際には少し奇妙です. たとえば、foo--barおそらく と は別々の単語としてfoo表示されるbarはずですが、it's実際にはits?は別々の単語として表示されるはずです。isalphaさらに言えば、「単語文字」のルールとして使用すると、たとえば、2ndとして表示されることも意味しndます。

そのisasciiため、単語の文字と区切り文字を区別するためのユース ケースに適したルールでない場合は、正しい区別を行う独自の関数を作成する必要があります。isalnum(c) || c == '\''このようなルールは、ロジック (例: ) または表 (128 の整数の配列のみ、関数は)で簡単に表現できますc >= 0 && c < 128 && word_char_table[c]。そのようにすると、後でコードを拡張して、Latin-1 や Unicode を処理したり、プログラム テキスト (英語のテキストとは異なる単語文字を使用) を処理したりできるという追加の利点があります。</p>

于 2013-08-07T17:24:49.290 に答える
0

単語をスペースで区切っているように見えるので、ちょうどいいと思います

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

も機能します。入力テキストの単語間に複数のスペースを入れないことを条件とします。

于 2013-08-07T17:23:41.240 に答える