统计字数的程序读取输入的字符并报告其中的单词个数。处理时有可以统计字符个数和行数。来看看这样一个程序包含哪些步骤。
首先,这个程序应该逐个读取字符,并且应该有些方法判断何时停止;第二,他应该能够识别并统计下列单位:字符、行和单词。下面是伪代码描述:
read a character
while there is more input
increment character count
if a line has been read,increment line count
if a word has been read,increment word count
read next character
前面已经有输入循环的模型了:
while((ch = getchar())!=STOP)
{
....
}
这里,STOP代表通知输入结束的ch取值。前面的示例程序已经使用了换行符和句号来用于该目的,但对于一个通用的单词统计程序这两个都不合适。现在我们暂且选择一个在文本中不常见的字符(|)。在后面会有一个更好的解决方案,以使程序即能处理文本文件又能处理键盘输入。
现在来考虑一下循环体。因为程序使用getchar()来输入字符,所以可以再每个循环周期通过递增一个计数器的值来统计字符。为了统计行数,程序可以检查换行符。如果字符是换行符,程序就递增行数计数器。有个问题是如果STOP字符出现在一行的中间该怎么办。行数计数器应不应该增加呢?一种做法是将他作为一个不完整行统计,也就是说 ,该行有字符而没有换行符。可以通过追踪前一个字符来识别这种情况。如果STOP之前所读入的最后一个字符不是换行符,就计为一个不完整行。
最棘手的部分是识别单词。首先,必须明确定义一个单词意味着什么。让我们以一个相对简单的方法将一个单词定义为不包括空白字符(也就是说,没有空格、制表符或换行符)的一系列字符。因此,“glymxck”和r2d2是单词。一个单词以程序首次遇到非空白字符开始,在下一个空白字符出现时结束。检测非空白字符最简单明了的判断表达式是这样的:
c != ' ' && c != '\n' && c != '\t' /* 当C不是空白字符时,该表达式为真*/
检测空白字符最简单明了的判断是:
c == ' ' c == '\n' || c == '\t' /*当C是空白字符时,该表达式为真*/
但是使用ctype.h的isspace()函数会更简单。如果该函数的参数是 空白字符,它就返回真。因此如果c是空白字符,isspace(c)为真;而如果c不是空白字符,!isspace(c)为真。
为了知道一个字符是不是在某单词里,可以再读一个单词的首字符时把一个标志(命名为inword)设置为1.也可以在此处递增单词技术。
然后,只要inword保持为1(或真),后续的非空白字符就不标记为一个单词的开始。到出现下一个空白字符是,必须将此标志重置为0(或假),并且程序准备搜索下一个单词。转换为伪代码是这样的:
if c is not whitespace and inword is false
set inword to true and count the word
if c is whitespace and inword is true
set inword to false
这种方法为每个单词开始时将inword设为1(真),而在每个单词结束时将其设为0(假)。仅在该标志从0变为1时对单词计数。如果在您的系统上可以使用_Bool型变量,可以包含stdboo.h头文件并用bool作为inword的类型,取值分别为ture何false.否则,就使用int类型,取值为0和1.
如果使用布尔型变量,通常的习惯是用变量自身的值作为判断条件。也就是说,用:
if (inword)
来代替:
if (inword == true)
并且用:
if (!inword)
来代替:
if(inword==false)
依据是,如果inword为true,则表达式inword == true 结果为true;而如果inword为false,则该表达式也为false。因此倒不如只用inword作为判断条件。与之类似,!inowrd与表达式inword == false值相同(非真即false,非假即true)。
以下附上完整源码:
#include #include #include
/*如果编译器较老,不支持C99,
则将以上#include 行注释,添加typedef enum{false=0,true=1}bool;*/
#define STOP '|'
int main(void)
{
char c;//读入字符
char prev;//前一个读入字符
long n_chars=0L;//字符数
int n_lines=0;//行数
int n_words=0;//单词数
int p_lines=0;//不完整的行数
bool inword=false;//如果c在一个单词中,则inword等于true
printf("Enter text to be analyzed(|to terminate):\n");
prev = '\n';//用于识别完整的行
while((c = getchar()) != STOP)
{
n_chars++;//统计字符
if(c == '\n')
{
n_lines ++;//统计行
}
if( !isspace() && !inword)
{
inword = true;//开始一个新单词
n_words ++;//统计单词
}
if(isspace(c) && inword)
{
inword = false;//到达单词的尾部
}
prev = c;//保存字符值
}
if(prev != '\n')
{
p_lines = 1;
}
printf("characters = %ld,word = %d,lines = %d",
n_chars,n_words,n_lines);
printf("partial lines = %d\n",p_lines);
return 0;
}