Как считать только слова, начинающиеся с прописной буквы в списке? - PullRequest
0 голосов
/ 15 мая 2019

Как считать слова, начинающиеся только с заглавных букв?

  • Найти все заглавные начальные слова (например, Any = 3)
  • Подсчитайте, сколько раз эти слова встречаются (например, Any = 3 + any + 4 = Any = 7)

См. Пример кода из этой демонстрации:

https://codeforwin.org/2018/02/c-program-count-occurrences-of-all-words-a-file.html

Пример кода:

https://onlinegdb.com/HJgWn-K2E

/**
* C program to count occurrences of all words in a file.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_WORDS   50

char *strlwr(char *str)
{
    unsigned char *p = (unsigned char *)str;

    while (*p) {
        *p = tolower((unsigned char)*p);
        p++;
    }

    return str;
}

int main()
{
    FILE *fptr;
    char path[100];
    int i, len, index, isUnique;

    // List of distinct words
    char words[MAX_WORDS][50];
    char word[50];

    // Count of distinct words
    int  count[MAX_WORDS];


    /* Input file path */
    printf("Enter file path: ");
    scanf("%s", path);


    /* Try to open file */
    fptr = fopen(path, "r");

    /* Exit if file not opened successfully */
    if (fptr == NULL)
    {
        printf("Unable to open file.\n");
        printf("Please check you have read privileges.\n");

        exit(EXIT_FAILURE);
    }

    // Initialize words count to 0
    for (i=0; i<MAX_WORDS; i++)
        count[i] = 0;




    index = 0;

    while (fscanf(fptr, "%s", word) != EOF)
    {
        // Convert word to lowercase
        strlwr(word);

        // Remove last punctuation character
        len = strlen(word);
        if (ispunct(word[len - 1]))
            word[len - 1] = '\0';


        // Check if word exits in list of all distinct words
        isUnique = 1;
        for (i=0; i<index && isUnique; i++)
        {
            if (strcmp(words[i], word) == 0)
                isUnique = 0;
        }

        // If word is unique then add it to distinct words list
        // and increment index. Otherwise increment occurrence
        // count of current word.
        if (isUnique)
        {
            strcpy(words[index], word);
            count[index]++;

            index++;
        }
        else
        {
            count[i - 1]++;
        }



    }

    // Close file
    fclose(fptr);


    /*
     * Print occurrences of all words in file.
     */
    printf("\nOccurrences of all distinct words in file: \n");
    for (i=0; i<index; i++)
    {
        /*
         * %-15s prints string in 15 character width.
         * - is used to print string left align inside
         * 15 character width space.
         */
        printf("%-15s %d\n", words[i], count[i]);
    }


    return 0;
}

В этом примере кода они делают все слова строчными буквами, а затем подсчитывают все эти слова.

Вместо этого: Как добавить слова в уникальный список только в том случае, если он начинается с заглавной буквы, а затем сосчитать все вхождения этого слова

Если вы объедините fscanf с if (isupper [0])

Файл Test.txt

Any girl jumped over one boy.
Some car skipped to some boy.
One town drove over the town.
Any town ran under some dog.
Some girl drove to a town.
The boy walked under any town.
A town jumped over any car.
Any boy jumped from a car.
A dog ran over a boy.
A girl ran to some car.
A car ran under the girl.
The car ran on any town.
One dog walked under any dog.
A car jumped on some town.
A boy ran to a boy.
The dog drove over a boy.
A boy jumped over the car.
Some car drove on some girl.
One boy drove under some girl.
A girl walked over some dog.

Ожидаемый результат:

Any  7
Some 3
One  4
The  6
A    8

Токовый выход:

any             7
girl            7
jumped          5
over            7
one             4
boy             10
some            10
car             9
skipped         1
to              4
town            8
drove           5
the             6
ran             6
under           5
dog             6
a               13
walked          3
from            1
on              3

Возможные решения:

    // skip the word if it does not contain a capital letter at start
    if (islower(word[0])) {
        continue;
    }

Затем создайте еще один цикл FOR , который проверяет, как часто эти слова появляются в файле, если они начинаются с в нижнем регистре или в верхнем регистре

1 Ответ

1 голос
/ 15 мая 2019

Вы работаете в правильном направлении, вам просто нужно немного переставить код. В то время как вы можете использовать отдельные массивы, чтобы попытаться отслеживать каждое уникальное слово, координируя этот индекс с индексом в массиве, содержащем число раз, когда слово встречается, и тем же индексом в другом массиве, показывающим, встречается ли слово в вашем файле с заглавной или нет - но есть лучший способ.

Всякий раз, когда вам приходится координировать различные типы данных как единое целое, вы должны думать struct. С помощью struct вы можете координировать каждое уникальное слово, будет ли оно отображаться заглавными буквами в файле, и сколько раз оно встречается (без учета регистра) как единое целое, например,

typedef struct {            /* use a struct to hold */
    char word[MAX_WORD];    /* lowercase word, and */
    int cap, count;         /* if it appeast capitalized, and its count */
} words_t;

Теперь вы можете просто создать массив words_t и иметь возможность добавлять каждый word (нижний регистр) в качестве слова в структуре, фиксировать, появляется ли оно когда-либо cap, выделенное курсивом, и общее число count раз это происходит.

Это упрощает логику в вашем коде. Теперь вы просто объявляете массив words_t, например

#define MAX_WORD     50     /* max word size */
#define MAX_WORDS   512     /* max number of words */
...
    /* Array of struct of distinct words, initialized all zero */
    words_t words[MAX_WORDS] = {{ .word = "" }};

Вы спрашиваете свое имя файла - , проверяющий каждый пользовательский ввод , например,

    /* Input file path */
    printf ("Enter file path: ");
    if (scanf ("%s", path) != 1) {  /* validate every input */
        fputs ("error: invalid file path or cancellation.\n", stderr);
        return 1;
    }

Теперь зациклите ваши слова - защищая как границы массива, так и читая каждое слово:

    while (index < MAX_WORDS &&                 /* protect array bounds  */
            fscanf (fptr, "%s", word) == 1) {   /* while valid word read */

Теперь суть логики, необходимой для хранения и отслеживания слов с заглавной буквы, вступает в игру. Сначала вам нужен флаг, чтобы проверить, является ли слово заглавным, чтобы захватить информацию до того, как вы преобразуете слово в нижний регистр (вместе с вашим isunique флагом). Вы определяете, является ли слово заглавным, просто проверяя первый символ с помощью isupper(), например,

        int iscap = 0, isunique = 1;    /* is captial, is unique flags */

        if (isupper (*word))            /* is the word uppercase */
            iscap = 1;

Вместо того, чтобы просто обрезать одну пунктуацию, вы можете так же легко обрезать все знаки препинания перед преобразованием слова в нижний регистр, например,

        /* remove all trailing punctuation characters */
        len = strlen (word);                    /* get length */
        while (len && ispunct(word[len - 1]))   /* only if len > 0 */
            word[--len] = 0;

        strlwr (word);                  /* convert word to lowercase */

Теперь все, что остается с точки зрения хранения данных, - это цикл, чтобы определить, является ли слово isunique, и если оно не , просто установите флаг cap, если iscap - ИСТИНА и увеличить счет. Если это уникально , то после выхода из цикла вы копируете слово в новый элемент в вашем массиве (используя memcpy у вас есть длина, нет необходимости повторного сканирования), и вы делаете то же самое вещь с cap и count, увеличивая index, когда закончите,

        /* check if word exits in list of all distinct words */
        for (i = 0; i < index; i++) {
            if (strcmp(words[i].word, word) == 0) {
                isunique = 0;               /* set unique flag zero */
                if (iscap)                  /* if capital flag set */
                    words[i].cap = iscap;   /* set capital flag in struct */
                words[i].count++;           /* increment word count */
                break;                      /* bail - done */
            }
        }
        if (isunique) { /* if unique, add to array, increment index */
            memcpy (words[index].word, word, len + 1);  /* have len */
            if (iscap)                      /* if cap flag set */
                words[index].cap = iscap;   /* set capital flag in struct */
            words[index++].count++;         /* increment count & index */
        }
    }
    fclose (fptr);  /* close file */

Все, что остается, - это циклически проходить по элементам, хранящимся в массиве, и проверять член .cap, чтобы определить, появляется ли слово заглавными перед печатью слова и сколько раз оно появляется ( note: your Ожидаемый результат: неверные значения в зависимости от вашего примера)

    /*
     * Print occurrences of all words in file.
     */
    puts ("\nOccurrences of all distinct words with Cap in file:");
    for (i = 0; i < index; i++) {
        if (words[i].cap) {
            strcpy (word, words[i].word);
            *word = toupper (*word);
            /*
             * %-15s prints string in 15 character width.
             * - is used to print string left align inside
             * 15 character width space.
             */
            printf("%-15s %d\n", word, words[i].count);
        }
    }

( примечание: использование puts вместо printf для "Occurrences of...", поскольку преобразование не требуется ... хороший компилятор оптимизирует это для вас)

В целом, вы можете сделать:

/**
 * C program to count occurrences of all words in a file.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>

#define MAX_WORD     50     /* max word size */
#define MAX_WORDS   512     /* max number of words */

#ifndef PATH_MAX
#define PATH_MAX   2048     /* max path (defined for Linux in limits.h) */
#endif

typedef struct {            /* use a struct to hold */
    char word[MAX_WORD];    /* lowercase word, and */
    int cap, count;         /* if it appeast capitalized, and its count */
} words_t;

char *strlwr (char *str)    /* no need for unsigned char */
{
    char *p = str;

    while (*p) {
        *p = tolower(*p);
        p++;
    }

    return str;
}

int main (void) {

    FILE *fptr;
    char path[PATH_MAX], word[MAX_WORD];
    size_t i, len, index = 0;

    /* Array of struct of distinct words, initialized all zero */
    words_t words[MAX_WORDS] = {{ .word = "" }};

    /* Input file path */
    printf ("Enter file path: ");
    if (scanf ("%s", path) != 1) {  /* validate every input */
        fputs ("error: invalid file path or cancellation.\n", stderr);
        return 1;
    }

    fptr = fopen (path, "r");   /* open file */
    if (fptr == NULL) {         /* validate file open */
        fputs ( "Unable to open file.\n"
                "Please check you have read privileges.\n", stderr);
        exit (EXIT_FAILURE);
    }

    while (index < MAX_WORDS &&                 /* protect array bounds  */
            fscanf (fptr, "%s", word) == 1) {   /* while valid word read */
        int iscap = 0, isunique = 1;    /* is captial, is unique flags */

        if (isupper (*word))            /* is the word uppercase */
            iscap = 1;

        /* remove all trailing punctuation characters */
        len = strlen (word);                    /* get length */
        while (len && ispunct(word[len - 1]))   /* only if len > 0 */
            word[--len] = 0;

        strlwr (word);                  /* convert word to lowercase */

        /* check if word exits in list of all distinct words */
        for (i = 0; i < index; i++) {
            if (strcmp(words[i].word, word) == 0) {
                isunique = 0;               /* set unique flag zero */
                if (iscap)                  /* if capital flag set */
                    words[i].cap = iscap;   /* set capital flag in struct */
                words[i].count++;           /* increment word count */
                break;                      /* bail - done */
            }
        }
        if (isunique) { /* if unique, add to array, increment index */
            memcpy (words[index].word, word, len + 1);  /* have len */
            if (iscap)                      /* if cap flag set */
                words[index].cap = iscap;   /* set capital flag in struct */
            words[index++].count++;         /* increment count & index */
        }
    }
    fclose (fptr);  /* close file */

    /*
     * Print occurrences of all words in file.
     */
    puts ("\nOccurrences of all distinct words with Cap in file:");
    for (i = 0; i < index; i++) {
        if (words[i].cap) {
            strcpy (word, words[i].word);
            *word = toupper (*word);
            /*
             * %-15s prints string in 15 character width.
             * - is used to print string left align inside
             * 15 character width space.
             */
            printf("%-15s %d\n", word, words[i].count);
        }
    }

    return 0;
}

Пример использования / Вывод

Использование вашего введенного ввода

$ ./bin/unique_words_with_cap
Enter file path: dat/girljumped.txt

Occurrences of all distinct words with Cap in file:
Any             7
One             4
Some            10
The             6
A               13

( примечание: "Some/some" появляется 10 раз, а "A/a" появляется 13 раз вместо 3/8, указанного в Ожидаемый результат: , который вы можно подтвердить простым подсчетом)

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...