Как посчитать количество гласных в файле пословно и прикрепить результат к словам? - PullRequest
1 голос
/ 26 мая 2020

Я пытаюсь написать код на C, который считывает n слов из файла и слово за словом изменяет содержимое.

Программа подсчитает количество гласных в каждом слове. Если количество гласных в текущем слове четное, программа поменяет местами гласные на пару из двух (без замены в случае нечетного числа), а затем добавит количество гласных к слову.

Например, если слово apple, измененное слово будет выглядеть как eppla_2vow.

Моя проблема в том, что я не совсем понимаю, как я должен внесите изменения слово в слово.

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

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

Я приведу другой пример, давайте скажем, содержимое файла:

apple juice strawberry can make pineapple

И измененные слова будут выглядеть так:

eppla_2vow juice_3vow strewbarry_2vow can_1vow meka_2vow penieppla_4vow

Ответы [ 2 ]

1 голос
/ 26 мая 2020

Это можно разбить на несколько подзадач:

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

Во-вторых, нам нужна функция, которая меняет местами гласные в строке. Метод с двумя указателями кажется для этого способом go. Пока передний и задний указатели не встретились, перебирайте передний указатель вперед, пока он не коснется гласной. На этом этапе уменьшите указатель назад, пока он не достигнет гласной, и поменяйте их местами. Продолжайте так менять местами, пока указатели не пересекутся. Как и выше, легко передать список символов для замены в строку.

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

Собираем все вместе:

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

После выполнения этого output.dat содержит:

eppla_2vow juice_3vow strewbarry_2vow can_1vow meka_2vow penieppla_4vow
1 голос
/ 26 мая 2020

Я бы реструктурировал программу, чтобы упростить задачу. Вот схема:

  • получить размер входного файла, например, stat()
  • выделить размер + 1 байт и поместить нулевой байт в конец
  • прочитать файл в выделенный буфер
  • определить небольшой буфер с достаточным пространством для слова + _XXvow байтов
  • сканировать выделенный буфер в al oop с помощью strtok()
  • копировать из strtok() адрес возврата в маленький локальный буфер
  • изменять байты в малом буфере (во время или после копирования) и выводить исправленное слово

Дополнительно: вместо набора многих тестов для символов гласных вы можете создать массив байтов для всех символов, инициализировать все до нуля, а затем заполнить места гласных заменяющими буквами; если какой-либо проиндексированный байт не равен нулю, замените гласную на новую и увеличьте количество гласных. Этот метод повышает эффективность за счет индексации массива вместо многих (тест + ветвь).

...