【问题标题】:Counting Syllables one char at a time [C]一次计算一个字符的音节 [C]
【发布时间】:2010-02-07 18:13:46
【问题描述】:

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

因此,考虑到这一点,我的程序是这样工作的:

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,它将从音节数中减去一个。 这会照顾到 e 在单词末尾不计为元音。

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

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

编辑:一些代码...

我有 if(句尾标记),然后是 else if(空格),然后是最后一个 else,它意味着只有可以形成单词的字母才会出现在这个块中。这是唯一应该对音节计数产生任何影响的代码块......

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 如果为 1,稍后在程序中将在音节数上加一。 skipSylb 用于标记最后一个字符是否也是音节。如果skipSylb = 1,那么这是一个元音块,我们只想在计数器上加一个。现在我有一个 isE 变量,它只是在下一次告诉程序最后一个字母是 E。这意味着,下一次通过 while 循环,如果它是句尾或空格,最后一个字母是 E (所以 isE = 1),那么我们加了一个太多的音节。

希望这会有所帮助。

由于该值实际上低于应有的值,我认为也许 i 从计数中减去的语句也很重要。 我使用这个 if 语句来决定何时从计数中减去:

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

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

【问题讨论】:

  • 请添加“作业”标签。人们不介意提供帮助,但您必须对此诚实。
  • 抱歉,没有意识到有这样的标签。
  • 尝试缩小出现问题的代码范围。现在,您向我们发布了一些内容,基本上可以告诉我们您打算代码要做什么——但如果代码做到了,它显然会正常工作。既然它没有,它显然并没有真正按照您的描述进行操作,但我们无法合理地猜测它正在在做什么。
  • 一个简单的可能性:Y 呢?
  • 定义元音的规则集很清楚,产生上述数字的相同文本没有使用Y。我认为我的逻辑有问题,所以我的想法的描述以上足以看出缺陷。但是,如果逻辑合理,那么我将使用一些代码块进行编辑。

标签: c text file-io character


【解决方案1】:

我还设置了它,以便当程序读取 !:;.?或空格,它将查看最后一个读取的字符,如果是 e,它将从音节数中减去一个。

这听起来不对。像“死”和“看”这样的词呢? 显然,只有当单词计数超过一个音节时,您才能减少计数。

在您的情况下,如果末尾的“e”不是元音组的一部分,则递减可能就足够了。

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

真正能帮助您的是调试输出。让程序告诉你它在做什么:

“读元音:e”

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

【讨论】:

  • 感谢您的输入,我在上面添加了一些代码。但老实说,我认为我只需要进行一些调试,看看我是否可以将其缩小到一个不起作用的代码块。
【解决方案2】:

你需要一个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。为了混合隐喻,条件句的一个大老鼠巢是一种现代版本的意大利面条代码。

至少通过将控制流组织到一个状态机中,您可以将一些逻辑压缩到一个平面中,从而更容易可视化操作并进行单独的更改。创建的结构虽然很少是最短的表达式,但至少很容易修改和逐步改变。

【讨论】:

  • 这是一个 C 问题,我认为你的(伪)代码会更清晰;在适当的地方。
【解决方案3】:

查看您的代码,我怀疑某些逻辑因过大而丢失。您的主要 sn-p 看起来相当于这样:

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 词干分析器中的步骤,以获取有关如何破解的一些指导以半有意义的方式升起英语单词。它旨在去除后缀,但我怀疑正在解决的问题足够相似,至少可以提供一点启发。

【讨论】:

  • 因为这是一个作业,我已经在我的原始帖子中定义了音节是什么。我知道在实践中它更难定义。为了理解我的代码,会发生这样的事情:一旦找到元音,它就会在音节数上加一。通过设置skipSylb = 1,这将覆盖单个元音和组。这意味着如果下一个字母是元音,它不会再次添加到计数中。我不确定您所说的 endSlyb = !skipSylb; 是什么意思,因为我以前从未见过这种符号。
  • enySylb=!skipSylb 中,'!'表示“不”,所以如果skipSylb==0endSylb 变为 1,如果skipSylb==1endSylb 变为 0。
猜你喜欢
  • 1970-01-01
  • 2016-06-24
  • 2011-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多