第16周项目2 单词的个数

本文介绍了一个简单的C++程序,用于统计给定字符串中的单词数量。通过遍历字符串并检查空格来确定单词边界,该程序能够准确地计算出单词总数。

/*
*Copyright (c)2014,烟台大学计算机与控制工程学院
*All rights reserved.
*文件名称:b.cpp
*作    者  张伟建
*完成日期:2014年12月16日
*版 本 号:v1.0
*
*问题描述:统计字符的单词个数
*输入描述:略
*输出描述:略
*/
#include <iostream>

using namespace std;
int pwordnum(char *str);
int main()
{
    char s[50]="hello world good morning";
    cout<<"单词的个数:"<<pwordnum(s)<<endl;
    return 0;
}
int pwordnum(char *str)
{
    int num=1;
    char *p;
    for(p=str; *p!='\0'; p++)
    {
        if(*p==' ')
            num++;
    }
    return num;
}



学习心得:一个空格可以代表一个单词。

<think>嗯,用户想用C语言编写一个程序,统计字符串中的数字个数、字母个数单词数量,直到遇到'*'停止。我需要仔细分析这个问题,并给出正确的实现方法。 首先,用户的需求有三个统计目标:数字字符、英文字母和英文单词的数量。停止条件是遇到'*'字符。我需要考虑如何逐个字符读取输入,并在遇到'*'时终止统计。 对于数字和字母的统计,相对直接。可以用循环逐个检查每个字符,判断是否是数字(isdigit函数)或字母(isalpha函数),然后累加相应的计数器。这部分应该没问题,但要注意字符的判断方法是否正确。 但单词数量的统计可能比较复杂。通常,单词是以空格分隔的连续字符序列。所以需要检测从非空格到空格或终止符的转换。例如,当当前字符是字母而前一个字符是空格时,可能表示新单词的开始。或者,可以使用状态变量,比如一个标志位表示是否正在读取单词,当遇到字母且之前是空格或初始状态时,计数器加一。但需要注意多个连续空格的情况,避免重复计数。 另外,用户希望输入直到遇到'*'停止,所以需要在读取每个字符时检查是否为'*',如果是则结束循环。这里需要注意输入的方式,可能需要使用getchar()逐个读取字符,直到遇到'*'为止。 可能的实现步骤: 1. 初始化三个计数器:数字、字母、单词,初始值都为0。 2. 使用一个循环,每次读取一个字符。 3. 如果字符是'*',退出循环。 4. 检查字符是否是数字,如果是,数字计数器加一。 5. 检查是否是字母,如果是,字母计数器加一。 6. 对于单词计数,需要判断何时增加计数器。通常,当遇到一个字母,并且之前处于非字母状态(比如空格或开始)时,视为新单词的开始。可以使用一个标志位in_word,初始为0,当遇到字母且in_word为0时,单词数加一,并将in_word设为1。当遇到非字母(如空格)时,将in_word设为0。 7. 注意,像逗号、句号等标点可能会影响单词的判断,但根据一般定义,可能假设单词由字母组成,其他字符作为分隔符。但题目中没有特别说明,可能只需以空格分隔。 但用户的问题中提到的是“英文单词的数量”,可能需要更精确的判断。例如,是否将连续的非空格字符视为一个单词?或者按照空格分隔。例如,"hello,world"可能被算作一个单词还是两个?如果用户希望按空格分隔,那么逻辑是基于空格来分割单词。这时候,每当遇到一个空格时,可能结束当前单词,然后下一个非空格字符视为新单词的开始。 因此,正确的单词计数逻辑可能如下: - 初始化in_word为0(表示不在单词中)。 - 遍历每个字符: - 如果当前字符是字母,并且in_word为0,则单词计数器加一,in_word设为1。 - 如果当前字符不是字母(比如空格或其他字符),则将in_word设为0。 这样,当连续的非字母字符出现时,不会重复计数。例如,"test!!test"会被视为两个单词吗?如果中间的符号不是字母,那么会被视为两个单词?或者中间的符号是否分割单词?这可能需要更明确的定义。但根据常见情况,可能单词由字母组成,非字母字符作为分隔符。因此,只要字符是字母,并且之前不在单词中,就增加单词数。其他情况下,in_word设为0。 但需要确保只有字母连续的序列算作一个单词。例如,如果输入是"a1b",这里的1不是字母,那么a和b会被算作两个单词吗?如果是的话,那么每当遇到字母时,如果之前不在单词中,则计数。否则,如果已经是单词中,继续。非字母字符会将in_word设为0。 这可能符合用户的预期。但需要明确用户的需求。这里可能需要假设单词是由连续的字母组成,其他字符作为分隔符。 现在,考虑程序的结构: 使用getchar()逐个读取字符,直到遇到'*'。 初始化变量: int digits = 0; int letters = 0; int words = 0; int in_word = 0; 循环: char c; while ((c = getchar()) != '*') { if (isdigit(c)) { digits++; } else if (isalpha(c)) { letters++; if (!in_word) { words++; in_word = 1; } } else { in_word = 0; // 其他字符,比如空格、标点等,处理吗? // 如果是空格,是否需要处理? } } 但这样可能有问题。例如,如果输入是"hello world",两个单词,会被正确计数。但如果是"hello,world!",中间的逗号和感叹号会导致in_word在遇到非字母时被设为0,因此在处理w时,in_word为0,所以words会增加。这样会将"hello,world"视为两个单词?这可能不符合用户预期,因为中间的逗号被视为分隔符。但用户可能希望单词是连续的字母,所以这里的逻辑是正确的。例如,"hello,world"会被视为两个单词:hello和world。 或者,用户是否希望将标点符号内的字母视为单词的一部分?例如,"don't"是否算作一个单词?这可能需要更复杂的处理,比如考虑撇号。但根据题目中的要求,可能用户只需要简单地用空格分隔,或者以非字母作为分隔符。由于题目中没有详细说明,可能需要按最简单的方式处理,即当字符是字母时,如果之前不在单词中,就增加单词数,否则继续。其他字符一律将in_word设为0。 这可能满足一般情况下的需求,比如当输入是空格分隔的单词时。 例如,输入是:"abc 123 def*",则字母数:6,数字数:3,单词数:2(abc和def)。是否正确?是的,因为中间的123不是字母,所以当处理d时,in_word是0,所以words加1。而前面的abc在处理a时,in_word是0,加1,之后b和c保持in_word为1。遇到空格后,in_word变为0。然后处理d时,再次加1。 所以,这样的逻辑是可行的。 测试案例: 输入:"Hello world 123 *" 输出:字母数:10(H e l l o w o r l d),数字数:3,单词数:2. 另一个案例:"test1 test2-test3*" 字母数:t e s t t e s t t e s t → 12?或者数字部分不算。这里test1中的1是数字,所以字母是t,e,s,t →4;test2是4个字母,test3是4个字母。总字母数是4+4+4=12?是的。数字数是1(test1中的1)+1(test2中的2)+1(test3中的3)=3。单词数:处理test1中的t,in_word是0,words+1;然后遇到1(数字),in_word设为0。接下来空格,in_word还是0。处理test2的t,in_word是0,words+1→2。然后遇到-,in_word设为0。处理test3的t,in_word是0,words+1→3。所以总单词数3。这可能是否符合预期? 用户可能希望单词数量是3,即test1视为一个单词吗?但根据当前逻辑,test1中的1是非字母,所以当处理t时,in_word是0,加1。接着处理e,s,t都是字母,in_word保持1。接着1是数字,此时in_word被设为0。因此,整个test1会被视为一个单词吗?不,因为处理到1的时候,是数字,此时会进入else分支,将in_word设为0。但是处理test1中的字母部分时,只有前面四个字母,此时in_word为1。当处理1时,它属于数字,所以进入isdigit的分支,不会触发else中的in_word=0。哦,这里有个问题,原来的代码中,非字母且非数字的字符才会触发else中的in_word=0。例如,当字符是数字时,不会触发else,所以in_word不会被设为0。这样,在test1的情况下,处理完字母t后,in_word是1。然后处理1,属于数字,所以不会进入else分支。因此,in_word仍然保持1。接着处理空格,这个时候字符是空格,进入else分支,in_word设为0。 这样的话,test1中的数字后面的空格才会导致in_word设为0。这会导致test1中的字母和数字部分被认为是同一个单词的一部分?例如,处理t时,in_word从0→1,words+1。接下来的e,s,t都是字母,in_word保持1。然后处理1,属于数字,此时进入isdigit的判断,增加digits,不会改变in_word。此时,in_word还是1。然后遇到空格,进入else分支,in_word设为0。因此,整个test1被视为一个单词,因为数字字符不影响in_word的状态,只有非字母且非数字的字符才会导致in_word被重置。这显然有问题,因为test1中的数字是跟在字母后面,此时in_word仍然是1,所以test1会被视为一个单词吗? 例如,输入是"test1",当处理到t,e,s,t时,in_word是1。然后处理1,属于数字,此时不会触发else,所以in_word保持1。因此,这个整个字符串会被视为一个单词吗?是的。但根据用户的需求,test1是否应该算作一个单词?可能用户的预期是,单词应该由纯字母组成,但此处的逻辑认为只要包含字母,并且中间没有非字母(非数字)的分隔符,就会视为一个单词。例如,test1中的数字作为单词的一部分,此时会被算作一个单词,而数字的存在不影响in_word的状态,因为只有当字符是非字母且非数字时才会触发in_word的复位。这可能不符合用户的预期。 这说明原来的逻辑存在错误。用户希望统计的是英文单词的数量,而通常英文单词由字母组成,数字和符号可能作为分隔符。因此,正确的做法应该是,只有字母连续出现时才视为单词的一部分,而任何非字母字符(包括数字)都会导致in_word复位。 因此,需要修改判断条件:当字符是字母时,处理字母计数和可能的单词计数;否则,如果是数字,只处理数字计数,并将in_word设为0;其他字符(如空格、标点)同样将in_word设为0。或者,更准确地说,任何非字母的字符都会导致in_word复位,而数字字符属于非字母,所以此时应该将in_word设为0。 因此,原代码中的else部分可能不正确。例如,在原来的代码中,数字字符不会触发else分支,因此in_word不会被重置。这会导致像test1这样的字符串被算作一个单词,因为处理到1的时候,属于数字,不会进入else,所以in_word仍然为1。因此,当处理完test1之后遇到空格时,才会触发in_word=0。所以,test1会被视为一个单词。 这显然不符合用户的预期。用户可能希望将test1视为一个单词吗?或者认为包含数字的不算单词? 例如,用户的问题描述中提到“统计字符串中的数字字符、英文字母和英文单词的数量”,这里的英文单词应该由纯字母组成,所以包含数字的字符串不应被视为单词。因此,需要调整逻辑,任何非字母字符都会导致in_word复位。 因此,正确的逻辑应该是: 当字符是字母时,增加letters,并检查in_word是否为0。如果in_word为0,则words加1,并设置in_word为1。 当字符不是字母时,不管是否是数字还是其他字符,都设置in_word为0。 这样,数字字符的出现会使得in_word被复位,所以在类似test1的情况下,处理到1时,会设置in_word为0。因此,test1中的test部分会被视为一个单词,而数字1不会影响,但后续的非字母字符将in_word设为0。 例如,输入是test1,处理t时in_word是0→words+1,in_word=1。处理e,s,t,in_word保持1。处理1,此时进入数字的判断,digits加1。然后,因为字符不是字母,所以执行else分支,设置in_word=0。因此,整个test1中的test部分是一个单词,后面的数字不影响,此时words=1。这是正确的,因为test1中的test部分是连续的字母,而数字1被处理后导致in_word=0。因此,test1会被视为一个单词吗?是的,因为在处理test的时候,单词已经被计数,但后面的数字不会计入单词。但根据新的逻辑,当处理到数字时,in_word被设置为0。这样,在test1的例子中,单词数仍然是1,对吗? 是的,因为处理test的时候,单词数被增加一次。处理数字时,in_word被设为0。但此时单词数已经被计数一次,所以是正确的。 另一个例子,输入是"a1b",如何处理?处理a是字母,in_word是0→words+1,in_word=1。接着1是数字→digits加1,并且设置in_word=0。然后处理b→字母,in_word是0→words+1。所以总单词数是2。这可能不符合用户的预期,因为a和b被数字分隔,但用户可能认为这是一个无效的单词。不过,根据逻辑,这两个字母被算作两个单词。这可能是否正确? 如果用户认为连续的字母才算作一个单词,那么a和b被非字母分隔,应视为两个单词。这可能合理。例如,"a,b"会被视为两个单词a和b。因此,这样的逻辑是正确的。 因此,正确的逻辑应该是:当字符是字母时,检查是否处于单词外,是的话增加单词计数。否则,如果是非字母字符,设置in_word为0。此时,数字字符和其他字符都会导致in_word被复位。 因此,代码需要调整,将数字字符的处理放在非字母的分支中。即,当字符是数字时,增加digits,并将in_word设为0?或者,更准确地说,当字符不是字母时,无论是否是数字,都将in_word设为0。 修改后的代码逻辑: 循环中,对于每个字符: 如果字符是数字:digits++,并设置in_word=0? 或者,不管是否是数字,只要不是字母,就设置in_word=0? 正确的做法应该是,当字符是字母时,处理字母计数,并可能增加单词数;否则,无论是否是数字还是其他字符,都将in_word设为0。 例如: if (isdigit(c)) { digits++; in_word = 0; // 这样是否正确? } else if (isalpha(c)) { letters++; if (!in_word) { words++; in_word = 1; } } else { in_word = 0; } 这样,当字符是数字时,in_word被设为0。这样,当处理类似test1的情况时,处理到数字时,in_word会被设为0。这样,当后面有其他字母时,才会重新计数单词。 例如,输入是test1test: 处理t→字母,in_word为0→words+1,in_word=1。 e,s,t→字母,in_word保持1。 1→数字→digits++,in_word=0. t→字母→in_word是0→words+1(总words=2),in_word=1. 因此,整个字符串test1test会被视为两个单词:test和test。这符合预期,因为中间的1将in_word复位,所以后面的t被视为新单词的开始。 这似乎更符合用户的预期,即每个连续的字母序列被视为一个单词,无论中间是否有数字或其他字符分隔。 但这样处理的话,当数字出现在字母中间时,会打断单词的连续性。例如,输入是"ab12cd",则会被视为两个单词:ab和cd。这可能正确,因为中间的数字分隔了它们。 因此,这样的逻辑是正确的。 现在,代码的正确结构应该如下: 初始化digits、letters、words为0,in_word为0。 循环读取字符,直到遇到'*': char c; while ((c = getchar()) != '*') { if (isdigit(c)) { digits++; in_word = 0; // 数字字符导致in_word复位 } else if (isalpha(c)) { letters++; if (!in_word) { words++; in_word = 1; } } else { in_word = 0; // 其他字符(如空格、标点)也复位in_word } } 这样,任何非字母的字符都会导致in_word被复位为0。字母只有在之前不在单词中的情况下才会增加单词计数。 现在,测试一些案例: 案例1: 输入:"Hello world 123*" 处理: H →字母,in_word=0→words=1,in_word=1. e →字母,in_word=1→不增加。 l →同上。 l →同上. o →同上. 空格→非字母,in_word=0. w→字母,in_word=0→words=2,in_word=1. o→... r→... l→... d→... 空格→in_word=0. 1→数字→digits=1,in_word=0. 2→digits=2,in_word=0. 3→digits=3,in_word=0. 遇到*,停止. 结果:letters=10(H e l l o w o r l d),digits=3,words=2。正确。 案例2: 输入:"a1b*" 处理: a→字母→words=1,in_word=1. 1→数字→digits=1,in_word=0. b→字母→in_word=0→words=2,in_word=1. 遇到*,停止. 结果:letters=2,digits=1,words=2. 这可能是否符合用户预期?如果用户认为a和b是两个单词,那么正确。否则,可能希望视为一个单词?但根据逻辑,中间的1分隔了它们,所以视为两个单词。 案例3: 输入:"test,test-test*" 处理: t→字母→words=1,in_word=1. e→... s→... t→... ,→非字母→in_word=0. t→字母→words=2,in_word=1. e→... s→... t→... -→非字母→in_word=0. t→字母→words=3,in_word=1. 遇到*,停止. 结果:letters=8(每个test有4字母,共两次?或者三个test?输入是"test,test-test",第三个test可能被截断?假设输入是"test,test-test",则四个字母test,接着四个test,再四个test?不,原输入是"test,test-test",即test(4)、test(4)、test(4)?不,原输入中的-test是t e s t?可能要看具体输入。假设这里输入是"test,test-test",处理到第四个字符是逗号,然后test,之后连字符,再test。所以总共有三个单词:test、test、test。因此,words=3,letters=4*3=12. 这样处理是正确的,因为每个test被非字母字符分隔,所以视为三个单词。 现在,这样的逻辑应该是正确的。 接下来,考虑如何编写代码。需要注意: - 使用标准库函数isdigit和isalpha,需要包含<ctype.h>头文件。 - 循环读取字符,直到遇到'*'。 - 需要处理可能的输入缓冲区问题,比如用户输入后换行符等,但根据问题描述,只要遇到'*'就停止,所以换行符或其他字符在'*'之前都会被处理。 代码的大致结构: #include <stdio.h> #include <ctype.h> int main() { int digits = 0, letters = 0, words = 0; int in_word = 0; char c; printf("请输入字符串(以*结束输入):\n"); while ((c = getchar()) != '*') { if (isdigit(c)) { digits++; in_word = 0; } else if (isalpha(c)) { letters++; if (!in_word) { words++; in_word = 1; } } else { in_word = 0; } } printf("字母数量: %d\n", letters); printf("数字数量: %d\n", digits); printf("单词数量: %d\n", words); return 0; } 但这里可能有一个问题:当输入中包含换行符或其他非字母数字字符时,例如用户输入"hello world*",则最后的'*'会被正确捕获,停止循环。但是,如果用户输入"hello*",则循环在读取到'*'时停止,正确处理。 现在,测试案例: 输入:Hello world 123* 输出: 字母数量: 10 数字数量:3 单词数量:2. 另一个测试案例,输入:a1b*,输出字母2,数字1,单词2. 另一个测试案例,输入:test,test-test*,输出字母12,数字0,单词3. 这应该正确。 因此,这段代码应该能够满足用户的需求。 另外,用户的问题中提到“直到遇到'*'停止计算”,所以程序应该在读取到'*'后立即停止,不再处理后面的字符。因此,代码中的循环条件正确。 最后,用户可能需要将结果输出,如示例中的函数count()可能返回统计结果。但根据问题描述,用户可能希望将代码结构化为一个函数,或者在主函数中实现。但用户的问题没有明确要求使用函数,所以主函数的实现可能足够。 综上,这样的代码应该满足用户的需求。</think>以下是用C语言实现统计字符串中数字、字母及单词数量的详细步骤: ### 实现步骤 1. **初始化计数器** 定义变量分别记录数字、字母和单词的数量,并设置`in_word`标志跟踪当前是否处于单词中。 2. **逐字符读取输入** 使用`getchar()`循环读取字符,直到遇到`*`时停止。 3. **分类统计字符** - **数字**:通过`isdigit()`判断,计数器加1,并重置`in_word`标志。 - **字母**:通过`isalpha()`判断,计数器加1。若当前不在单词中,则单词计数器加1并标记`in_word`。 - **其他字符**:直接重置`in_word`标志。 ### 示例代码 ```c #include <stdio.h> #include <ctype.h> int main() { int digits = 0, letters = 0, words = 0; int in_word = 0; // 标记是否处于单词中 char c; printf("请输入字符串(以*结束输入):\n"); while ((c = getchar()) != '*') { if (isdigit(c)) { // 统计数字 digits++; in_word = 0; // 遇到数字,标记不在单词中 } else if (isalpha(c)) { // 统计字母 letters++; if (!in_word) { // 若此前不在单词中,则新增一个单词 words++; in_word = 1; // 标记进入单词状态 } } else { // 其他字符(空格、符号等) in_word = 0; // 标记不在单词中 } } printf("字母数量: %d\n", letters); printf("数字数量: %d\n", digits); printf("单词数量: %d\n", words); return 0; } ``` ### 代码说明 - **逐字符处理**:通过`getchar()`逐个读取字符,确保实时处理输入流[^1]。 - **单词统计逻辑**:通过`in_word`标志确保连续字母仅计为一个单词(如`"hello123world"`计为2单词)。 - **停止条件**:遇到`*`立即终止统计,符合题目要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值