通过有限状态机实现文章的单词统计

提示:通过有限状态机实现的简单单词统计功能


有限状态机简介

对于大学学过数电的同学,状态机理解可能比较简单,因为会需要画状态转换图,这里只会以一个简单的例子来抛转引玉,对有限状态机感兴趣的可自行查阅更多资料来研究。
所谓的状态机,抽象出来,就是一个状态转换图,用有限状态机的思维来处理问题,最关键的在于:
(1)该问题/模型能抽象成几个状态;
(2)什么条件满足时会由一个状态转换到另一个状态
(3)应初始化为什么状态

单词统计状态抽象

以我们的主题为例,统计一篇文章中的单词个数,假设文章内如如下:
hello, we are testing a finite-state machine;
well, let’s get start.
我们知道单词一般是由一个或多个连续字母组成的,一个字符只能是组成单词的一部分或非单词的一部分,因此我们将状态分为两个:
单词状态----该字符是组成单词的一部分;非单词状态----该字符不是组成单词的一部分

单词统计状态转换条件

(1)从一个字母到另外一个字母,仍在同一个单词中;
(2)但从一个字母变成一个符号、空格,一个单词结束,从单词状态转换到非单词状态;
(3)从一个符号、空格变成另一个符号、空格,认为仍处于非单词状态;
(4)从一个符号、空格变成一个字母,从非单词状态转化到单词状态;
用状态转换图表示如下:

在这里插入图片描述

单词统计初始化状态

解决了状态和状态间的转换关系我们还要解决初始化状态的问题,初始化状态直接决定了一个状态机是否能正常工作,对于有些状态机,自动运行后始终能循环回到初始化状态,但有的状态机不行。这里很简单,我们最开始单词个数肯定是0,因此初始化未非单词状态。

代码实现

通过上述的分析,我们可以实现如下代码:

//words_cal.c
#include <stdio.h>
#define ST_WORD      0            //单词状态 
#define ST_SYMB      1            //符号状态
#define INIT         ST_SYMB      //初始状态

//判断读入的字符是否是符号,是返回1,否返回0
int is_symbol(const char c)
{
	if((' ' == c) || ('\n' == c) || ('\t' == c) || ('\"' == c) || ('\'' 	   == c) || ('+' == c) || (',' == c) || (';' == c))
		return 1;			
	return 0;
}
int count_word(const char *filename)
{
	int status = INIT;
	FILE *fp = fopen(filename, "r");
	if(fp == NULL) return -1;
	int word_num = 0;
	char c;
	while(((c = fgetc(fp)) != EOF))
	{
		//理论上应先判断当前状态,对应处理每个状态内容,可以简化写成如下
		if(is_symbol(c))
		{
			status = ST_SYMB;			
		}else if(status == ST_SYMB)
		{
			status = ST_SYMB;
			word_num++;
		}			
	}
	fclose(fp);
	return word_num;
}
//输入要统计的文件路径作为参数
int main(char argc, char *argv[])
{
	if(argc < 2) return -2;
	printf("word_num: %d\n", count_word(argv[1]));
	return 0;
}

进一步优化

我们在实际运行过程中,要考虑到一些特殊情况,如当出现符号"-“时,我们上面是没做处理,即默认是单词的,实际上当遇到”-"时,假如后面紧跟着字母,或紧跟’\n’,新行又紧跟字母,那么我们认为仍为同一个单词,但如果再是这样“–”或“------”,这时我们就应将它视为新的状态了。这里不继续往下完善,感兴趣的刚好可以作为练习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值