字数总是少一。我尝试在 "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;
}
在您的
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
仅在从不在字内到字内的过渡时增加,在每个字的第一个字符上触发)
#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
个单词。仔细查看,如果您有任何疑问,请告诉我。
无需复制或重新发明标准库函数,以下内容似乎有效。
#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;
}
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
.
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;
}
unsigned char
函数使用
is...()
值,因为这些函数没有为大多数负值定义。
的字符串可能超过长度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;
}
is...()
!!
将任何非零值转换为 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 == '!';