Исключить слово, если оно присутствует в массиве слов - PullRequest
6 голосов
/ 16 мая 2019

Учитывая этот код, который подсчитывает все вхождения, как вы удаляете общие слова?

Например, если слово входит в число 100 лучших английских слов, не считается этим словом.

Если вы берете наиболее распространенные 100 слов в соответствии с Википедией, как вы добавляете их в массив и проверяете, чтобы они не учитывались в списке: https://en.wikipedia.org/wiki/Most_common_words_in_English

Топ 100 самых распространенных слов в форме массива:

#define NUMBER_OF_STRING 100
#define MAX_STRING_SIZE   50

char commonWords[NUMBER_OF_STRING][MAX_STRING_SIZE] = {"the", "be", "to", "of", "and", "a", "in", "that", "have", "I", "it", "for", "not", "on", "with", "he", "as", "you", "do", "at", "this", "but", "his", "by", "from", "they", "we", "say", "her", "she", "or", "an", "will", "my", "one", "all", "would", "there", "their", "what", "so", "up", "out", "if", "about", "who", "get", "which", "go", "me", "when", "make", "can", "like", "time", "no", "just", "him", "know", "take", "people", "into", "year", "your", "good", "some", "could", "them", "see", "other", "than", "then", "now", "look", "only", "come", "its", "over", "think", "also", "back", "after", "use", "two", "how", "our", "work", "first", "well", "way", "even", "new", "want", "because", "any", "these", "give", "day", "most", "us"};

Пример кода:

/**
 * 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  20000     /* max word size */
#define MAX_WORDS     8     /* initial number of struct to allocate */

#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, max_words = MAX_WORDS;

    /* pointer to allocated block of max_words struct initialized zero */
    words_t *words = calloc (max_words, sizeof *words);
    if (!words) {   /* valdiate every allocation */
        perror ("calloc-words");
        exit (EXIT_FAILURE);
    }

    /* 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 (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 */
            if (index == max_words) {       /* is realloc needed? */
                /* always use a temporary pointer with realloc */
                void *tmp = realloc (words, 2 * max_words * sizeof *words);
                if (!tmp) { /* validate every allocation */
                    perror ("realloc-words");
                    break;  /* don't exit, original data still valid */
                }
                words = tmp;    /* assign reallocated block to words */
                /* (optional) set all new memory to zero */
                memset (words + max_words, 0, max_words * sizeof *words);
                max_words *= 2; /* update max_words to reflect new limit */
            }
            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("%-8d %s\n", words[i].count, word);
        }
    }
    free (words);

    return 0;
}

Текстовый файл для проверки: (cars.txt)

A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of car say they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods.[2][3]

Cars came into global use during the 20th century, and developed economies depend on them. The year 1886 is regarded as the birth year of the modern car when German inventor Karl Benz patented his Benz Patent-Motorwagen. Cars became widely available in the early 20th century. One of the first cars accessible to the masses was the 1908 Model T, an American car manufactured by the Ford Motor Company. Cars were rapidly adopted in the US, where they replaced animal-drawn carriages and carts, but took much longer to be accepted in Western Europe and other parts of the world.

Cars have controls for driving, parking, passenger comfort, and a variety of lights. Over the decades, additional features and controls have been added to vehicles, making them progressively more complex. These include rear reversing cameras, air conditioning, navigation systems, and in-car entertainment. Most cars in use in the 2010s are propelled by an internal combustion engine, fueled by the combustion of fossil fuels. Electric cars, which were invented early in the history of the car, began to become commercially available in 2008.

There are costs and benefits to car use. The costs include acquiring the vehicle, interest payments (if the car is financed), repairs and maintenance, fuel, depreciation, driving time, parking fees, taxes, and insurance.[4] The costs to society include maintaining roads, land use, road congestion, air pollution, public health, health care, and disposing of the vehicle at the end of its life. Road traffic accidents are the largest cause of injury-related deaths worldwide.[5]

The benefits include on-demand transportation, mobility, independence, and convenience.[6] The societal benefits include economic benefits, such as job and wealth creation from the automotive industry, transportation provision, societal well-being from leisure and travel opportunities, and revenue generation from the taxes. People's ability to move flexibly from place to place has far-reaching implications for the nature of societies.[7] There are around 1 billion cars in use worldwide. The numbers are increasing rapidly, especially in China, India and other newly industrialized countries.[8]

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

Occurrences of all distinct words with Cap in file:
3        A
2        Motor
2        Most
2        One
8        Cars
29       The
1        German
1        Karl
2        Benz
1        Patent-motorwagen
1        Model
1        T
1        American
1        Ford
1        Company
1        Us
1        Western
1        Europe
1        Over
1        These
1        Electric
2        There
2        Road
1        People's
1        China
1        India

Ожидаемый результат: (только пример)

2        Motor
1        German
1        Karl
2        Benz
1        Patent-motorwagen
1        Model
1        T
1        American
1        Ford
1        Company

РЕДАКТИРОВАТЬ Обновление: Возможные решения:

время и продолжить (не работает)
// skip the word if it is a common word
for (int i = 0; i < NUMBER_OF_STRING; i++) {
    if (strcmp(word, commonWords[i])==0) {
        continue;
    }
}

Ответы [ 4 ]

3 голосов
/ 19 мая 2019

Отфильтруйте common word перед добавлением word в список words. Я сделал функцию fiter, как показано ниже:

int isCommonWord(char * word)
{
    int i = 0;
    for (i = 0; i < NUMBER_OF_STRING; i++) {
        if (strcmp(commonWords[i], word) == 0) return 1;
    }
    return 0;
}

И, отфильтруйте слово перед добавлением в массив слов. Пожалуйста, обратитесь ко 2-й строке кода, который я изменил, как показано ниже:

if (isunique) { /* if unique, add to array, increment index */
    if (!isCommonWord(word)) {
        if (index == max_words) {       /* is realloc needed? */
            /* always use a temporary pointer with realloc */
            void *tmp = realloc(words, 2 * max_words * sizeof *words);
            if (!tmp) { /* validate every allocation */
                perror("realloc-words");
                break;  /* don't exit, original data still valid */
            }
            words = (words_t *)tmp;    /* assign reallocated block to words */
            /* (optional) set all new memory to zero */
            memset(words + max_words, 0, max_words * sizeof *words);
            max_words *= 2; /* update max_words to reflect new limit */
        }
        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 */
    }
}

Я думаю, что результат правильный, как показано ниже:

Enter file path: cars.txt

Occurrences of all distinct words with Cap in file:
2        Motor
8        Cars
1        German
1        Karl
2        Benz
1        Patent-motorwagen
1        Model
1        T
1        American
1        Ford
1        Company
1        Western
1        Europe
1        Electric
2        Road
1        People's
1        China
1        India
3 голосов
/ 19 мая 2019

Несколько более эффективным способом было бы использовать один вызов strstr, а не пытаться сравнивать каждое из 100 самых распространенных слов. Поскольку вы знаете 100 самых распространенных слов, и они не изменятся, вы можете легко определить самый длинный из 7 символов. Другими словами, вам нужно только проверить, является ли word одним из наиболее распространенных, если он меньше:

#define TOP_LEN       8     /* longest string in TOP100 + nul-character */

Поскольку слова не меняются, вы можете пойти дальше и:

const char TOP100[] = " the be to of and a in that have i it for not on with"
                " he as you do at this but his by from they we say her she or"
                " an will my one all would there their what so up out if about"
                " who get which go me when make can like time no just him know"
                " take people into year your good some could them see other"
                " than then now look only come its over think also back after"
                " use two how our work first well way even new want because"
                " any these give day most us ";

( примечание: space до и space после каждого слова, которое позволяет вам создать teststr для поиска с strstr, добавив пробел по обе стороны от вашего word. 'I' был преобразован в нижний регистр для работы после strlwr (word);)

( также обратите внимание: вы также можете использовать константный литерал с #define TOP100 " the ... us ", но он будет ужасно заворачиваться и прокручиваться со страницы здесь - до вас)

С вашей константной строкой из 100 наиболее распространенных слов требуется только одно добавление:

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

        /* check against 100 most common words (TOP100) */
        if (len < TOP_LEN) {                    /* word less than TOP_LEN? */
            char teststr[TOP_LEN * 2];          /* buffer for " word " */
            sprintf (teststr, " %s ", word);    /* create teststr */
            if (strstr (TOP100, teststr))       /* check if in TOP100 */
                continue;                       /* if so, get next word */
        }
        ...

Вы видите выше, вы проверяете, содержит ли слово 7 символов или меньше (в противном случае нет необходимости проверять наиболее распространенное слово). Затем вы объявляете teststr для хранения строки с пробелом на каждом конце. (так как самое длинное общее слово в 7-символьном, то 7-символьный плюс 2 пробела - 9-символьный, плюс нуль-символ - 10, поэтому 16-символный более чем уместен здесь.)

Простой вызов sprintf - это все, что нужно, чтобы поставить пробелы на каждом конце word, а затем один вызов strstr - это все, что нужно, чтобы убедиться, что word находится внутри Топ 100 самых распространенных слов. Если это так, не нужно идти дальше, просто continue и получите следующее слово.

Если поместить его в код полностью, вы получите:

/**
 * 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  20000     /* max word size */
#define MAX_WORDS     8     /* initial number of struct to allocate */
#define TOP_LEN       8     /* longest string in TOP100 */

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

const char TOP100[] = " the be to of and a in that have i it for not on with"
                " he as you do at this but his by from they we say her she or"
                " an will my one all would there their what so up out if about"
                " who get which go me when make can like time no just him know"
                " take people into year your good some could them see other"
                " than then now look only come its over think also back after"
                " use two how our work first well way even new want because"
                " any these give day most us ";

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, max_words = MAX_WORDS;

    /* pointer to allocated block of max_words struct initialized zero */
    words_t *words = calloc (max_words, sizeof *words);
    if (!words) {   /* valdiate every allocation */
        perror ("calloc-words");
        exit (EXIT_FAILURE);
    }

    /* 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 (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 against 100 most common words (TOP100) */
        if (len < TOP_LEN) {                    /* word less than TOP_LEN? */
            char teststr[TOP_LEN * 2];          /* buffer for " word " */
            sprintf (teststr, " %s ", word);    /* create teststr */
            if (strstr (TOP100, teststr))       /* check if in TOP100 */
                continue;                       /* if so, get next word */
        }

        /* 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 */
            if (index == max_words) {       /* is realloc needed? */
                /* always use a temporary pointer with realloc */
                void *tmp = realloc (words, 2 * max_words * sizeof *words);
                if (!tmp) { /* validate every allocation */
                    perror ("realloc-words");
                    break;  /* don't exit, original data still valid */
                }
                words = tmp;    /* assign reallocated block to words */
                /* (optional) set all new memory to zero */
                memset (words + max_words, 0, max_words * sizeof *words);
                max_words *= 2; /* update max_words to reflect new limit */
            }
            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("%-8d %s\n", words[i].count, word);
        }
    }
    free (words);

    return 0;
}

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

Как и в прошлый раз, ваш Ожидаемый вывод: (только для примера) неверен, потому что в вашем коде нет ничего для удаления множественное число , приписывает или множественное число обладает , поэтому ваш вывод с вашим файлом cars.txt будет:

$ ./bin/unique_words_exclude_top_100
Enter file path: dat/cars.txt

Occurrences of all distinct words with Cap in file:
2        Motor
8        Cars
1        German
1        Karl
2        Benz
1        Patent-motorwagen
1        Model
1        T
1        American
1        Ford
1        Company
1        Western
1        Europe
1        Electric
2        Road
1        People's
1        China
1        India

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

2 голосов
/ 19 мая 2019

Это, очевидно, не работает, потому что не пропускает слово, если оно является общим словом , как в вводящем в заблуждение комментарии, но пропускает текущую итерацию и продолжает проверкуСледующее слово в списке общих слов

// skip the word if it is a common word
for (int i = 0; i < NUMBER_OF_STRING; i++) {
    if (strcmp(word, commonWords[i])==0) {
        continue;
    }
}

continue повлияет только на самый внутренний цикл.Кроме того, после цикла ничего не меняется

Чтобы исправить это, нужно разорвать внешний цикл

nextword:
while (fscanf (fptr, "%s", word) == 1) // read the word
    for (int i = 0; i < NUMBER_OF_STRING; i++) {
        if (strcmp(word, commonWords[i])==0) {
            goto nextword; // skip current word
        }
    }
/// ...
}

Или, если вы не хотите использовать goto тогда нужно использовать другую переменную

int isCommonWord = 0;
while (fscanf (fptr, "%s", word) == 1) // read the word
    for (int i = 0; i < NUMBER_OF_STRING; i++) {
        if (strcmp(word, commonWords[i])==0) {
            isCommonWord = 1;
            break; // exit the for loop
        }
    }
    if (isCommonWord)
        continue;  // get the next word
/// ...
}

В любом случае, ваша реализация довольно неэффективна.В основном это словарь , который отображается из строки (слова) в целое число (то есть количество слов).Словарь может быть отсортирован (например, std::map в C ++) или на основе хеша (std::unordered_map в C ++).Поскольку вы не сортируете массив, вы всегда должны просматривать весь список.Если массив отсортирован, то с помощью бинарный поиск значительно сократит поиск.Чтобы проверить список из 128 элементов, вам нужно всего лишь 7 сравнений вместо 128, как в случае несортированного списка

Но прежде чем искать слово в словаре, вам нужно проверить, является ли слово общим или нетпервый.Это делается путем проверки, существует ли слово в общем слове установить или нет.Опять же, набор может быть реализован несортированным (медленным), отсортированным (лучше, std::set в C ++) или на основе хеша (самый быстрый, но требует больше памяти, std::unordered_set в C ++).Разница между множеством и словарем состоит в том, что каждая запись словаря содержит пару (ключ, значение), тогда как значение также является ключом в наборе.Проверка цикла for strcmp(word, commonWords[i])==0 выше - это простой обход набора.В любом случае, как только вы найдете слово в наборе, пропустите текущий цикл while, а , а не цикл for, как я уже говорил выше.Это будет работать

0 голосов
/ 19 мая 2019

Продолжение внешних циклов - это случай, когда рекомендуется goto.

Добавьте метку до того, как:

outer:
while (fscanf (fptr, "%s", word) == 1)  { ... }

И измените возможное решение вопроса на:

for (int i = 0; i < NUMBER_OF_STRING; i++) {
    if (strcmp(word, commonWords[i])==0) {
        goto outer;
    }
}

В вашем текущем решении continue просто продолжает внутренний цикл for.

EDIT


В зависимости от вашей программы, изменение программы следующим образом должно работать:

.
.
.

outer:
while (fscanf (fptr, "%s", word) == 1) {
    .
    .
    .

    strlwr(word);

    for (int i = 0; i < NUMBER_OF_STRING; i++) {
        if (strcmp(word, commonWords[i])==0) {
            goto outer;
        }
    }

    .
    .
    .
}

.
.
.

Функция для этого будет выглядеть следующим образом:

int isCommon(char *word) {
    for (int i = 0; i < NUMBER_OF_STRING; i++) {
        if (strcmp(word, commonWords[i])==0) {
            return 1;
        }
    }
    return 0;
}

int main() {
    .
    .
    .

    while (fscanf (fptr, "%s", word) == 1) {
        .
        .
        .

        strlwr(word);

        if(isCommon(word))
            continue;

        .
        .
        .
    }

    .
    .
    .
}

Обратите внимание, что при использовании этой функции вам больше не требуется goto;простого continue будет достаточно.

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