首页 > 解决方案 > 计算数组中的音节

问题描述

我正在尝试计算传递给数组的字符串的每个单词中的所有音节。

一个音节算作两个相邻的元音(a、e、i、o、u、y)。例如,“peel”中的“ee”计为 1 个音节。但是,“juked”中的“u”和“e”算作2个音节。单词末尾的“e”不算作音节。此外,即使前面的规则不适用,每个单词也至少有 1 个音节。

我有一个文件,其中包含我传递给数组的大字符串(单词、空格和换行符)。我有通过计算每个单词和换行符之间的空格来计算每个单词的代码。见下文:

for (i = 0; i < lengthOfFile; i++)
{
    if (charArray[i] == ' ' || charArray[i] == '\n')
    {
      wordCount++;
    }
  }

charArray传入数组的文件在哪里(freads),是文件中lengthOfFile的总字节数(fseek)wordCount是计算的总字数。

从这里开始,我需要以某种方式计算数组中每个单词的音节,但不知道从哪里开始。

标签: c

解决方案


如果你仍然有麻烦,那只是因为你想太多了。每当您计算、确定频率等时,您通常可以使用“状态循环”来简化事情。状态循环只不过是一个循环,您循环遍历每个字符(或其他)并处理您发现自己所处的任何状态,例如:

  • 我读过任何字符吗?(如果没有,处理该状态);
  • 当前字符是空格吗?(如果是这样,为简单起见,假设没有多个空格,你已经到了一个单词的结尾,处理那个状态);
  • 当前字符是非空格非元音吗?(如果是这样,如果我的最后一个字符是元音,则增加我的音节数);和
  • 无论当前字符的分类如何,我都需要做什么?(输出它,设置last = current,等等..)

基本上就是这样,可以转换成一个循环,其中包含许多测试来处理每个状态。您还可以添加一个检查,以确保当您到达单词末尾时检查您的音节计数是否为零,以确保单词 like"my""he"被计为单个音节。

总而言之,您可以编写一个基本实现,例如:

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

int main (void) {

    char c, last = 0;                       /* current & last char */
    const char *vowels = "AEIOUYaeiouy";    /* vowels (plus Yy) */
    size_t syllcnt = 0, totalcnt = 0;       /* word syllable cnt & total */

    while ((c = getchar()) != EOF) {        /* read each character */
        if (!last) {                        /* if 1st char (no last) */
            putchar (c);                    /* just output it */
            last = c;                       /* set last */
            continue;                       /* go get next */
        }

        if (isspace (c)) {                  /* if space, end of word */
            if (!syllcnt)                   /* if no syll, it's 1 (he, my) */
                syllcnt = 1;
            printf (" - %zu\n", syllcnt);   /* output syll cnt and '\n' */
            totalcnt += syllcnt;            /* add to total */
            syllcnt = 0;                    /* reset syllcnt to zero */
        }   /* otherwise */
        else if (!strchr (vowels, c))       /* if not vowel */
            if (strchr (vowels, last))      /* and last was vowel */
                syllcnt++;                  /* increment syllcnt */

        if (!isspace (c))                   /* if not space */
            putchar (c);                    /* output it */
        last = c;                           /* set last = c */
    }
    printf ("\n  total syllables: %zu\n", totalcnt);
}

注意:如上所述,这个简单的示例实现不考虑单词之间的多个空格 - 您可以通过检查是否简单地将其添加为另一个需要的条件!isspace (last)。您能弄清楚应该在哪里添加检查吗?提示:它被添加到现有的检查&&——微调留给你)

示例使用/输出

$ echo "my dog eats banannas he peels while getting juked" | ./syllablecnt
my - 1
dog - 1
eats - 1
banannas - 3
he - 1
peels - 1
while - 1
getting - 2
juked - 2

  total syllables: 13

如果您需要从文件中读取单词,只需将文件作为输入重定向到 上的程序stdin,例如

./syllablecnt < inputfile

编辑 - 从文件读取到动态分配的缓冲区

继关于希望从文件(或stdin)读取到动态大小的缓冲区然后遍历缓冲区以输出每个单词的音节和总音节的评论之后,您可以执行以下操作,只需从一个将文件放入最初分配的包含 8 个字符的缓冲区中,并根据需要重新分配(每次realloc需要 a 时将分配大小加倍)。这是一个相当标准且相当有效的缓冲增长策略。您可以自由地将其增长到您喜欢的任何大小,但要避免许多小的兔子颗粒重新分配,因为从计算的角度来看,内存分配相对昂贵。

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

#define NCHAR 8     /* initial characters to allocate */

int main (int argc, char **argv) {

    char c, last = 0, *buffer;              /* current, last & pointer */
    const char *vowels = "AEIOUYaeiouy";    /* vowels */
    size_t syllcnt = 0, totalcnt = 0,       /* word syllable cnt & total */
            n = 0, size = NCHAR;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("fopen-file");
        return 1;
    }

    /* allocate/validate initial NCHAR buffer size */
    if (!(buffer = malloc (size))) {
        perror ("malloc-buffer");
        return 1;
    }

    while ((c = fgetc(fp)) != EOF) {        /* read each character */
        buffer[n++] = c;                    /* store, increment count */
        if (n == size) {                    /* reallocate as required */
            void *tmp = realloc (buffer, 2 * size);
            if (!tmp) {                     /* validate realloc */
                perror ("realloc-tmp");
                break;      /* still n good chars in buffer */
            }
            buffer = tmp;   /* assign reallocated block to buffer */
            size *= 2;      /* update allocated size */
        }
    }
    if (fp != stdin)        /* close file if not stdin */
        fclose (fp);

    for (size_t i = 0; i < n; i++) {        /* loop over all characters */
        c = buffer[i];                      /* set to c to reuse code */
        if (!last) {                        /* if 1st char (no last) */
            putchar (c);                    /* just output it */
            last = c;                       /* set last */
            continue;                       /* go get next */
        }

        if (isspace(c) && !isspace(last)) { /* if space, end of word */
            if (!syllcnt)                   /* if no syll, it's 1 (he, my) */
                syllcnt = 1;
            printf (" - %zu\n", syllcnt);   /* output syll cnt and '\n' */
            totalcnt += syllcnt;            /* add to total */
            syllcnt = 0;                    /* reset syllcnt to zero */
        }   /* otherwise */
        else if (!strchr (vowels, c))       /* if not vowel */
            if (strchr (vowels, last))      /* and last was vowel */
                syllcnt++;                  /* increment syllcnt */

        if (!isspace (c))                   /* if not space */
            putchar (c);                    /* output it */
        last = c;                           /* set last = c */
    }
    free (buffer);      /* don't forget to free what you allocate */

    printf ("\n  total syllables: %zu\n", totalcnt);
}

(您可以使用fgets或使用 POSIX执行相同的操作,或者使用您的orgetline一次全部分配,然后在一次调用中将整个文件分配到缓冲区中 - 由您决定)fseek/ftellstatfread

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有 2 个责任:(1)始终保留指向内存块起始地址的指针,(2)它可以在它不存在时被释放更需要。

您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的范围,尝试读取或基于未初始化的值进行条件跳转,最后确认释放所有分配的内存。

对于 Linuxvalgrind是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。

$ valgrind ./bin/syllablecnt_array dat/syllables.txt
==19517== Memcheck, a memory error detector
==19517== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==19517== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==19517== Command: ./bin/syllablecnt_array dat/syllables.txt
==19517==
my - 1
dog - 1
eats - 1
banannas - 3
he - 1
peels - 1
while - 1
getting - 2
juked - 2

  total syllables: 13
==19517==
==19517== HEAP SUMMARY:
==19517==     in use at exit: 0 bytes in 0 blocks
==19517==   total heap usage: 5 allocs, 5 frees, 672 bytes allocated
==19517==
==19517== All heap blocks were freed -- no leaks are possible
==19517==
==19517== For counts of detected and suppressed errors, rerun with: -v
==19517== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放所有已分配的内存并且没有内存错误。

如果您还有其他问题,请仔细查看并告诉我。


推荐阅读