Вы работаете в правильном направлении, вам просто нужно немного переставить код. В то время как вы можете использовать отдельные массивы, чтобы попытаться отслеживать каждое уникальное слово, координируя этот индекс с индексом в массиве, содержащем число раз, когда слово встречается, и тем же индексом в другом массиве, показывающим, встречается ли слово в вашем файле с заглавной или нет - но есть лучший способ.
Всякий раз, когда вам приходится координировать различные типы данных как единое целое, вы должны думать 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
, указанного в Ожидаемый результат: , который вы можно подтвердить простым подсчетом)
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.