How to count number of vowels from file word by word and attach the results to the words?

拜拜、爱过 提交于 2021-01-28 09:03:29

问题


I am trying to write a code in C that reads n words from a file and modifies the content word by word.

The program will count the number of vowels in each word. If the number of vowels in the current word is even, the program will swap the vowels in pair of two (no swapping in case of odd number), then it will attach the number of vowels to the word.

For example if the word is apple , the modified word will look like eppla_2vow .

My problem is that I don't quite know how am I supposed to make the modifications word by word.

     FILE *f = fopen("input.dat","r");
     int i;
     int bufflen=256;
     char buff[bufflen];

     while(n)
     {
      fscanf(f,"%s",buff);
      n--;
     }

     int vowels=0;

     for(i=0; buff[i]!='\0'; i++)
     {
          if (buff[i] == 'a' || buff[i] == 'e' || buff[i] == 'i' ||
          buff[i] == 'o' || buff[i] == 'u' || buff[i] == 'A' ||
          buff[i] == 'E' || buff[i] == 'I' || buff[i] == 'O' ||
          buff[i] == 'U')
          { vowel++;}

          if (buff[i] == ' ')
          {
           vowels=0;
          }
     }

I'm not even sure if I iterate over the string the right way in order to be able to make those modifications.

I will give another example, let's say the content of the file is:

apple juice strawberry can make pineapple

And the modified words will look like:

eppla_2vow juice_3vow strewbarry_2vow can_1vow meka_2vow penieppla_4vow

回答1:


This can be broken into a few sub-tasks:

First, we need a function to count the number of vowels in a string. That's pretty straightforward. We could generalize it to count the number of occurrences of any chars in a string in another string without any trouble.

Second, we need a function that swaps the vowels in a string. The two-pointer technique seems like the way to go for this. While the front and back pointers haven't met, iterate the front pointer forward until it lands on a vowel. At this point, decrement the back pointer until it hits a vowel and swap them. Keep swapping like that until the pointers cross. As above, it's easy to pass the character list to swap into the string.

Other than that, everything else is boilerplate--chunking the string on spaces and IO. Writing results back to a file instead of a string makes it easier to deal with reallocation for the _Nvow requirement; you can use fprintf to glue the word and count together.

Putting it all together:

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

int str_count_in_chars(char *start, char *end, char *chars) {
    int count = 0;

    for (; start != end; count += !!strchr(chars, *(start++)));

    return count;
}

void str_swap_in_chars(size_t str_len, char **str, char *chars) {
    for (int front = 0, back = str_len - 1; front < back; front++) {
        if (strchr(chars, (*str)[front])) {
            for (; !strchr(chars, (*str)[back]); back--);

            char tmp = (*str)[front];
            (*str)[front] = (*str)[back];
            (*str)[back--] = tmp;
        }
    }
}

char *file_to_str(FILE *fin) {
    int buf_len = 64;
    char buf[buf_len];
    char *str = malloc(buf_len);
    str[0] = '\0';

    for (int i = 1; fgets(buf, buf_len, fin); i++) {
        if (!(str = realloc(str, i * buf_len))) {
            fprintf(stderr, "%s:%d realloc failed\n", __FILE__, __LINE__);
            exit(1);
        }

        strcat(str, buf);
    }

    return str;
}

int main() {
    char *vowels = "aeiou";
    FILE *fin = fopen("input.dat", "r");
    FILE *fout = fopen("output.dat", "w");

    if (!fin || !fout) {
        fprintf(stderr, "%s:%d fopen failed\n", __FILE__, __LINE__);
        exit(1);
    }

    char *words = file_to_str(fin);
    fclose(fin);
    int words_len = strlen(words);

    for (int i = 0; i < words_len;) {
        if (isspace(words[i])) {
            fputc(words[i++], fout);
            continue;
        }

        int start = i;

        for (; i < words_len && !isspace(words[i]); i++);

        char *word = words + start;
        int word_len = i - start;
        int vowel_count = str_count_in_chars(word, words + i, vowels);

        if (vowel_count % 2 == 0) {
            str_swap_in_chars(word_len, &word, vowels);
        }

        fprintf(fout, "%.*s_%dvow", word_len, word, vowel_count);
    }

    fclose(fout); 
    free(words);
    return 0;
}

After executing this, output.dat contains:

eppla_2vow juice_3vow strewbarry_2vow can_1vow meka_2vow penieppla_4vow



回答2:


I'd restructure the program to make things easier. Here's an outline:

  • get the input file size, eg stat()
  • allocate size+1 bytes and place a null byte at the end
  • read the file into the allocated buffer
  • define a small buffer with sufficient space for a word + _XXvow bytes
  • scan the allocated buffer in a loop with strtok()
  • copy from strtok() return address into small local buffer
  • modify bytes in the small buffer (during or after copying) and output the revised word

Extra: instead of the set of many tests for vowel chars, you could create an array of bytes for all chars, init everything to zero, then fill the vowel locations with a replacement letter; when any indexed byte is non-zero, replace the vowel with the new one and increment a vowel count. This method gains efficiency from indexing an array instead of many (test + branch).



来源:https://stackoverflow.com/questions/62028883/how-to-count-number-of-vowels-from-file-word-by-word-and-attach-the-results-to-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!