C/C++小案例:汉语自动分词器

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++小案例:汉语自动分词器相关的知识,希望对你有一定的参考价值。

成果

一、模型设计

1.1 汉语自动分词:

1.1.1 基本理论:

词是自然语言中能够独立运用的最小单位,是自然语言处理的基本单位。自动词法分析就是利用计算机对自然语言的形态 (morphology) 进行分析,判断词的结构和类别等。词性或称词类(Part-of-Speech, POS)是词汇最重要的特性,是连接词汇到句法的桥梁。

1.1.2 算法基本思想:

正向最大匹配算法 (Forward MaxMatch, FMM) 描述:

假设句子:S = c1c2…cn ,某一词:w = c1c2…cm,m 为词典中最长词的字数。

1)令 i=0,当前指针 pi 指向输入字串的初始位置,执行下面的操作。
(2)计算当前指针 pi 到字串末端的字数(即未被切分字串的长度)n,如果 n=1,转 第四步,结束算法。否则,令 m=词典中最长单词的字数,如果 n<m,  令 m=n;
(3)从当前 pi 起取 m 个汉字作为词 wi,判断:
  	a.如果 wi 确实是词典中的词,则在 wi 后添加一个切分标志,转(c);
  	b.如果 wi 不是词典中的词且 wi 的长度大于 1,将wi 从右端去掉一个字,转(a)步;否则(wi 的长度等于 1),则在 wi 后添加一个切分标志(单字),执行 (c)步;
	c.根据 wi 的长度修改指针 pi 的位置,如果 pi 指向字串末端,转(4),否则,i=i+1,返回第二步;
(4)输出切分结果,结束分词程序。

1.1.3 算法评价:

优点:

  • 程序简单易行,开发周期短;
  • 仅需要很少的语言资源(词表),不需要任何词法、句法、语义资源;

缺点:

  • 歧义消解的能力差;

  • 切分正确率不高,一般在 95%左右。

二、系统设计

2.1 汉语自动分词:

2.1.1 数据结构:

unordered_map<string, int> StrInt_Hash : 哈希表存储词典(便于查询)

2.1.2 算法实现:

  • 对词典进行预处理,截取出所有中文汉字。

    循环读入字符串(遇到空格刚好读出一个字符串),直到文件结束。在此过程中,记录下词典中最长词的字节数。

    实现函数:void InitText(string infile);

  • 正向最大匹配算法。

    对汉语自动分词的正向匹配算法的实现(模型方法中有详细叙述),并将生成好的分词结果写入到文件中。

    实现函数:void PositiveMaxMatch(string _infile, string _outfile);

2.1.3 算法评估:

理论上,时间复杂度最差为:(Maxlen*Maxlen) (Maxlen 代表词典中最长词的字节数)

三、开发环境

操作系统:Windows 10
编程语言:C/C++
开发工具:Visual Studio 2017

四、源码

项目链接:
https://download.csdn.net/download/weixin_45525272/65216294

源代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <ctime>

using namespace std;
/// 预处理
#define MAX(a,b)	a>b?a:b		// 获取两个值中最大的
#define MIN(a,b)	a<b?a:b		// 获取两个值中最小的
#define ERROR_0 cerr << "Open error !!!" << endl; exit(1);	// 文件打开出错提示

int MaxLen;								// 词典中最长词的字节数
unordered_map<string, int> StrInt_Hash;	// 哈希表存储词典(便于查询)

const string ini_file = "1998-01-2003版-带音.txt";	// 词典
const string infile = "in.txt";						// 需要分词的文件
const string outfile = "out.txt";					// 分词后的文件
string project_time = "project_time.txt";			// 存储整个程序所运行的时间的文件

// 对词典进行预处理,截取出所有中文汉字
void InitText(string _infile)

	// 打开文件
	ifstream file_in;
	file_in.open(_infile);
	if (!file_in)
	
		ERROR_0;
	

	string str_tmp, str;
	int pos;
	MaxLen = 0;
	// 循环读入字符串(遇到空格刚好读出一个字符串),直到文件结束。
	// 在此过程中,记录下词典中最长词的字节数
	while (file_in >>str_tmp)
	
		pos = str_tmp.find("/");
		str = str_tmp.substr(0,pos);
		if (str.size() > MaxLen) 
			MaxLen = str.size();
		
		StrInt_Hash[str] = 1;
	

	// 关闭文件
	file_in.close();
	file_in.clear();


/// 正想最大匹配算法
void PositiveMaxMatch(string _infile, string _outfile)

	// 初始化
	InitText(ini_file);

	// 打开文件
	ifstream file_in;
	ofstream file_out;
	file_in.open(_infile);
	file_out.open(_outfile);
	if (!file_in)
	 
		ERROR_0;
	
	if (!file_out)
	
		ERROR_0;
	

	// 开始计时
	ofstream file_out_time;
	file_out_time.open(project_time);
	if (!file_out_time)
	
		ERROR_0;
	
	clock_t myStart, myFinish;
	double time_total;
	myStart = clock();

	/// 匹配算法
	std::ostringstream tmp;
	tmp << file_in.rdbuf();
	string text_tmp = tmp.str();

	int myBegin = 0;
	int myEnd = text_tmp.size();
	while (myBegin< myEnd)
	
		string str;
		int num;
		// 从最大长度的哈希元素进行查找,找不到长度-1,直到找到匹配的
		for (num=MIN(MaxLen,(text_tmp.size()-myBegin));num>0;num--)
		
			str = text_tmp.substr(myBegin,num);
			// 如果在哈希表中能找到并且,那么就写进去
			if (StrInt_Hash.find(str)!=StrInt_Hash.end())
			
				file_out << str;
				myBegin += num;
				break;
			
		
		// 如果没找到,那么不构成词,单独划分
		if (0 == num) 
			file_out << text_tmp.substr(myBegin, 1);
			myBegin += 1;
		
		file_out << "/";
	

	// 结束计时
	myFinish = clock();
	time_total = (double)(myFinish - myStart) / CLOCKS_PER_SEC;	// 计算运行总时间
	file_out_time << "运行时间为: " << time_total << " 秒。" << endl;
	
	// 关闭文件
	file_out_time.close();
	file_out_time.clear();
	file_out.close();
	file_out.clear();
	file_in.close();
	file_in.clear();


int main()

	PositiveMaxMatch(infile,outfile);
	return 0;

以上是关于C/C++小案例:汉语自动分词器的主要内容,如果未能解决你的问题,请参考以下文章

开源(开放)中文分词引擎评测

自然语言处理中“中文分词”技术中“自动切分”的几点理解

中文分词哪家强?11款分词引擎大比拼!

汉语分词工具的研发-----

简单的中文分词算法

收藏:11款开放中文分词引擎大比拼