为什么计数器变量出现一个单词的缩写?

问题描述 投票:0回答:5

字数总是少一。我尝试在 "i < len;" I've tried removing the space after "Text: " in the get_string prompt. For example, the prompt entry "One fish. Two fish. Red fish. Blue fish." compiles and the output for letters is correct, 29 letters, the output for words is WRONG(差 1)上添加 +1 - +10 — 7 个单词(应该是 8),句子的输出也是正确的 — 4 个句子。我假设 "isblank原型“int count_words(string sample)”中的“不计算最后一个单词,因为最后一个单词以句点结尾。将计数器设置为 1 而不是 0 是个好主意,或者是否有更好的方法来获取最后一个单词词?

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

int count_letters(string sample);
int count_words(string sample);
int count_sentences(string sample);

int main(void)
{
    string sample = get_string("Text: ");
    printf("%s\n", sample);

    int lettercount = count_letters(sample);
    printf("%i letters\n", lettercount);

    int wordcount = count_words(sample);
    printf("%i words\n", wordcount);

    int sentencescount = count_sentences(sample);
    printf("%i sentences\n", sentencescount);

}

int count_letters(string sample)
{
    int counter = 0;
    int len = strlen(sample);
    for (int i = 0; i < len; i++)
    {
        if (isalpha(sample[i]))
        {
            counter++;
        }
    }
    return counter;
}

int count_words(string sample)
{
    int counter = 0;
    int len = strlen(sample);
    for (int i = 0; i < len; i++)
    {
        if (isblank(sample[i]))
        {
            counter++;
        }
    }
    return counter;
}

int count_sentences(string sample)
{
    int counter = 0;
    int len = strlen(sample);
    for (int i = 0; i < len; i++)
    {
        if ((sample[i] == '.') || (sample[i] == '?') || (sample[i] == '!'))
        {
            counter++;
        }
    }
    return counter;
}
c cs50 c-strings counting function-definition
5个回答
2
投票

在您的

count_words()
函数中,您没有正确考虑是否存在前导空格、多个包含的空格字符和尾随空格。本质上,您将每个空格视为一个词。

虽然你可以用库函数来处理这个问题(@Fe203 使用

scrcspn()
/
strspn()
是一个很好的例子),使用一个简单的循环单词读取空格是另一种非常有效的方法(并且也可以很好地处理字符串文字/常量字符串。)跟踪事物的状态适用于许多问题。 对于你的字数统计,你可以做一些像下面这样简单的事情,使用

in_word

作为你的状态变量来跟踪你是在一个单词中阅读字符还是在一个单词阅读空格之前,之间或之后,例如

/* returns the number of whitespace separated words in str */
size_t count_words (const char *str)
{
    size_t words = 0;
    int in_word = 0;

    while (*str) {
        if (isspace ((unsigned char)*str))
            in_word = 0;
        else {
            if (!in_word)
                words++;
            in_word = 1;
        }
        str++;
    }

    return words;
}

注意:

字数words仅在从不在字内到字内的过渡时增加,在每个字的第一个字符上触发)

无耻地从@Fe203 借用一些额外的空白字符的示例并将字符串分成两部分可能是:

#include <stdio.h> #include <ctype.h> /* returns the number of whitespace separated words in str */ size_t count_words (const char *str) { size_t words = 0; int in_word = 0; while (*str) { if (isspace ((unsigned char)*str)) in_word = 0; else { if (!in_word) words++; in_word = 1; } str++; } return words; } int main (void) { printf ("words = %zu\n", count_words ( "One fish Two fish Red Fish Blue Fish" ) ); printf ("words = %zu\n", count_words ( " One fish Two fish Red Fish Blue Fish" ) ); printf ("words = %zu\n", count_words ( "One fish Two fish Red Fish Blue Fish " ) ); printf ("words = %zu\n", count_words ( " One fish Two fish " "Red Fish Blue Fish " ) ); return 0; }

结果是一样的,每个字符串 
8

个单词。仔细查看,如果您有任何疑问,请告诉我。

    


2
投票

无需复制或重新发明标准库函数,以下内容似乎有效。

#include <stdio.h> #include <string.h> int cntWords( char *str ) { int cnt = 0; str += strspn( str, " " ); // discard leading spaces while( *str ) { cnt++; str += strcspn( str, " " ); // find next SP str += strspn( str, " " ); // find next that is not SP } return cnt; } int main( void ) { printf( "words = %d\n", cntWords( "One fish Two fish Red Fish Blue Fish" ) ); printf( "words = %d\n", cntWords( " One fish Two fish Red Fish Blue Fish" ) ); printf( "words = %d\n", cntWords( "One fish Two fish Red Fish Blue Fish " ) ); printf( "words = %d\n", cntWords( " One fish Two fish Red Fish Blue Fish " ) ); return 0; }

words = 8
words = 8
words = 8
words = 8

编辑

该功能可以做得更紧凑:
int cntWords( char *str ) { int cnt = 0; while( *str ) { str += strspn( str, " " ); // find next non-space cnt += *str != '\0'; str += strcspn( str, " " ); // find next space } return cnt; }



1
投票
count_words

不考虑最后一个单词,因为它后面没有空格。

一般情况下,如果单词之间有多个空格字符或者字符串包含前导或尾随空格,该函数将错误地计算单词。

并且使用函数

strlen

是低效和多余的。

可以通过以下方式定义函数。

int count_words( string sample ) { int counter = 0; while ( *sample ) { while ( isblank( ( unsigned char )*sample ) ) ++sample; if ( *sample ) { ++counter; while ( *sample && !isblank( ( unsigned char )*sample ) ) ++sample; } } return counter; }

虽然像这样声明函数会好得多

size_t count_words( const char *sample ) { size_t counter = 0; while ( *sample ) { while ( isblank( ( unsigned char )*sample ) ) ++sample; if ( *sample ) { ++counter; while ( *sample && !isblank( ( unsigned char )*sample ) ) ++sample; } } return counter; }

这里有一个演示程序。

#include <stdio.h> #include <ctype.h> size_t count_words( const char *sample ) { size_t counter = 0; while (*sample) { while (isblank( ( unsigned char )*sample )) ++sample; if (*sample) { ++counter; while (*sample && !isblank( ( unsigned char )*sample )) ++sample; } } return counter; } int main( void ) { const char *sample = "One fish. Two fish. Red fish. Blue fish."; printf( "There are %zu words.\n", count_words( sample ) ); }

程序输出为

There are 8 words.

函数
count_sentences

也不正确。例如对于这个字符串

"What?!"
函数返回两个句子而不是一个。
功能可以像上面显示的功能一样实现

count_words

.

    


0
投票

int count_words(string sample) { int counter = 1; int len = strlen(sample); if(len == 0) { return 0; } for (int i = 0; i < len; i++) { if (isblank(sample[i])) { counter++; } } return counter; }

我会用 strtok 来做,真的没有别的原因,只是它为我计算了实际的单词,它实际上更复杂。

int count_words(char *sample) { char *cpy = NULL; char *token = NULL; int word_count = 0; /* I believe strtok will mangle the string so I'll make a copy of it */ cpy = calloc(1, strlen(sample) + 1); if(!cpy) { return -1; } strcpy(cpy, sample); token = strtok(cpy, " "); while(token) { word_count++; token = strtok(NULL, " "); } free(cpy); return word_count; }



0
投票

    最好为
  • unsigned char

    函数使用

    is...()
    值,因为这些函数没有为大多数负值定义。
    
    

  • 非常
  • long

    的字符串可能超过长度INT_MAX。最好用

    size_t
    来计算字母/单词以处理所有字符串。
    
    

  • 不是迭代到字符串的长度,而是迭代直到读取一个
  • 空字符

    。这会跳过不必要的(和昂贵的)之前的strlen()电话。

    
    

  • 计算单词的简单方法:计算从非字母到字母的转换。
比许多其他方法更简单,更不容易出错。


size_t count_words(const char *str) { size_t words = 0; const unsigned char *us = (const unsigned char *) str; unsigned char previous = 0; // Some non-letter while (*us) { if (isalpha(*us) && !isalpha(previous)) words++; previous = *us; us++; } return words; }

计算字母只需要传递 1 次字符串,而不是像 OP 的代码那样传递 2 次。

    is...()
  • 函数返回 0 或非零。使用
    !!
    将任何非零值转换为 1.
    
    
  • size_t count_letters(const char *str) { size_t letters = 0; const unsigned char *us = (const unsigned char*) str; while (*us) { letters += !!isalpha(*us); us++; } return letters; }
数句类似

// letters += !!isalpha(*us); sentences += *us == '.' || *us == '?' || *us == '!';

© www.soinside.com 2019 - 2024. All rights reserved.