一次计数音节一个字符[C]

时间:2010-02-07 18:13:47

标签: c text file-io character

我正在编写一个从文件中读取文本的程序,并确定该文件的句子数,单词数和音节数。诀窍是,它一次只能读取一个字符,并使用它。这意味着它不能只将整个文件存储在一个数组中。

因此,考虑到这一点,继续我的计划如何运作:

while(character != EOF)
{
    check if the character is a end-of-sentence marker (?:;.!)
    check if the character is whitespace (' ' \t \n)
    (must be a letter now)
    check if the letter is a vowel
}

使用状态机方法,每次循环通过时,某些触发器为1或0,这会影响计数。我在计算句子或单词时没有遇到任何麻烦,但是音节正在给我带来麻烦。我使用的音节定义是任何元音或元音组计为1个音节,但是单词末尾的单个e不算作音节。

考虑到这一点,我创建了代码

if character = 'A' || 'E' ... || 'o' || 'u'
    if the last character wasnt a vowel then
    set the flag for the letter being a vowel.
    (so that next time through, it doesnt get counted)
    and add one to the syllable count.
    if the last character was a vowel, then dont change the flag and don't
    add to the count. 

现在我遇到的问题,是我对给定文本文件的计数,非常低。 给定的数量是57个音节,36个单词和3个句子。我的句子是正确的,与单词相同,但我的音节数只有35。

我也设置好,以便当程序读取!:;。?或者是空格,它将查看最后读取的字符,如果是e,则将从音节计数中取出一个。 这样就可以在不计入元音的单词结尾处进行处理。

因此,考虑到这一点,我知道我的方法必定有问题才能获得如此巨大的差异。我一定是忘了什么。

有没有人有一些建议?我不想包括我的整个程序,但如果需要,我可以包含某些块。

编辑:一些代码......

我有if(句末标记),否则if(空格),然后是最后的其他条件,只需要可以形成单词的字母就在这个区块中。这是唯一一个对音节计数有任何影响的代码块......

if(chrctr == 'A' || chrctr == 'E' || chrctr == 'I' || chrctr == 'O' || chrctr == 'U' || chrctr == 'a' || chrctr == 'e' || chrctr == 'i' || chrctr == 'o'  || chrctr == 'u')
        {
            if(chrctr == 'E' || chrctr == 'e')
            {
                isE = 1;
            }
            else
            {
                isE = 0;
            }
            if(skipSylb != 1)
            {
                endSylb = 1;
                skipSylb = 1;
            }
            else
            {
                endSylb = 0;
                skipSylb = 1;
            }
        }
        else
        {
            endSylb = 0;
            skipSylb = 0;

        }

所以要解释一下...... endSylb if 1,稍后在程序中会添加一个音节数。 skipSylb用于标记最后一个字符是否也是一个音节。如果skipSylb = 1,那么这是一个元音块,我们只想在计数器中添加一个元音。现在我有一个isE变量,它只是在下一次告诉程序时最后一个字母是E.这意味着,下一次通过while循环,如果它是句子的结尾,或者是空格,最后一个字母是E (所以isE = 1),然后我们添加了太多的音节。

希望这会有所帮助。

由于该值实际上低于它应该是什么,我想也许我从计数中减去的陈述也很重要。 我使用这个if语句来决定何时减去计数:

 if(isE == 1)
       {
           countSylb --;
       } 

当字符是空格或句子结尾字符时,会发生此语句。 我想不出任何其他相关的东西,但我仍然觉得我没有包括足够的东西。 哦,如果有什么不清楚,请告诉我。

3 个答案:

答案 0 :(得分:2)

  

我也设置好,以便当程序读取!:;。?或者是空格,它会查看最后读取的字符,如果是e,它将取消一个音节数。

这听起来不对。那些像“死”和“看”这样的词呢? 显然,如果单词计为多个音节,你只能减少计数。

在你的情况下,如果最后的'e'不是元音组的一部分,那么减少可能就足够了。

如果这没有帮助:也许你在阅读辅音后没有清除元音标志?我无法从你的代码中看出来。

真正有用的是调试输出。让程序告诉你它在做什么:

“读元音:e”

“不计算元音e,因为[...]”

答案 1 :(得分:1)

您需要Finite State Machine


从某种意义上说,每个程序都是状态机,但通常在“状态机”的编程球拍中,我们指的是一个严格组织的循环,它具有以下特点:

while (1) {
  switch(current_state) {
    case STATE_IDLE:
      if (evaluate some condition)
        next_state = STATE_THIS;
      else
        next_state = STATE_THAT;
      break
    case STATE_THIS:
      // some other logic here
      break;
    case STATE_THAT:
      // yet more
      break;
  }
  state = next_state;
}

是的,您可以使用general spaghetti code解决此类程序。虽然传统的意大利面条代码不再具有文字跳跃,但是有一种思想学派能够在单个函数中对许多条件和嵌套条件进行分组,以便最小化cyclomatic complexity。为了混合隐喻,条件的大鼠窝是意大利面条代码的现代版本。

至少将控制流组织到一个状态机中,您可以将一些逻辑压缩到一个平面中,并且可视化操作并进行单独更改变得更加容易。创建一个结构,尽管很少使用最短的表达式,但至少很容易修改并逐渐改变。

答案 2 :(得分:0)

看看你的代码,我怀疑一些逻辑在过大的情况下已经丢失了。您的主要代码段看起来与以下内容相同:

chrctr = tolower(chrctr);

if (strchr(chrctr, "aeiou")) {
    isE = (chrctr == 'e');
    endSylb = !skipSylb;
    skipSylb = 1; // May not be you want, but it's what you have.
}
else {
    skipSylb = endSylb = 0;
}

就我个人而言,我认为尝试以算法计算音节几乎是没有希望的,但如果你真的想要,我会看一下Porter词干分析器中的步骤,以获得有关如何打破的一些指导半有意义的英语单词。它旨在剥离后缀,但我怀疑正在解决的问题足够相似,至少可以提供一些灵感。