博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于字典的【正向最大减字】分词算法实现
阅读量:5917 次
发布时间:2019-06-19

本文共 3832 字,大约阅读时间需要 12 分钟。

基于字典的的正向最大减字匹配算法,在《搜索引擎原理、技术与系统》提到过,可以说是最简单的中文分词算法之一。本文简要介绍实现过程,并附上实现源代码,一起学习。该算法实现主要是基于一个词典,进行分词,所以词典质量直接影响分词的结果。但是算法上也存在一些硬伤,举个例子,”参加过世界杯的选手”。无论用多丰富的词典,此算法均会分成“参加 过世 界 杯 的 选手”。

 

词典

词典采用GBK编码,格式为“ID SP 词语 SP 频率”(),只需要读取每一行,拿到两个空格(SP)之间的词语,然后放到一个C++ STL的set对象即可。在加载词典的同时,可以算出最大词长nMaxWordLen,这个值会在后面的分词使用到。

 

分词

从句子的最左边开始,逐字节遍历。每次分词时,首先截取nMaxWordLen个字节,并在词典中搜寻,如果找到了,就分词。如果找不到,就递减字节,如此往复,直到只剩下一个字节为止,这时就判断是ASCII还是汉字,如果是前者,直接分割,后者就将当前字节和下一个字节一起分割。这样直到遍历完所有字节。

 

代码

/* * dict_seg.cpp * 基于字典的分词 *  Created on: 2012-6-16 *      Author: bourneli */#include 
#include
#include
#include
#include
using namespace std;#define NL 0x0A // new line#define CR 0x0D // carrige return#define SP 0x20 // space#define GBK_HB_MIN 0x80 // minimum of gbk high byte#define DICT_PATH "words.gbk.dict" // 字典路径#define TEXT_PATH "sentence.txt" // 句子文本路径/** * 加载词典 * @param string sDictPath 字典路径 * @param set
oDict 字典 * @param int nMaxLen 字典中的最长词的字节数 */void LoadDictionary(const string& sDictPath, set
& oDict, int& nMaxLen);/** * 采用基于词典的最大正向匹配分词 * @param string sSen 需要分词的句子 * @param set
字典 * @param int 字典中的最长词的字节数 * @param vector
分词后的结果 */void SegmentSentence(const string& sSen, const set
& oDict, int nMaxLen, vector
& vecWords);int main(int argc ,char** argv) { set
oDict; int nMax = 0; LoadDictionary(DICT_PATH, oDict, nMax); // 获取句子 ifstream oReader(TEXT_PATH); if (!oReader.is_open()) { cout << "Fail to open file : " << TEXT_PATH; } string sSen = ""; getline(oReader, sSen); oReader.close(); cout << "Original Sentence: " << sSen << endl; /** * 采用正向最大匹配规则分词 */ vector
vecSeg; SegmentSentence(sSen, oDict, nMax, vecSeg); // 输出分词结果 cout << "Segment: "; for (vector
::const_iterator cItr = vecSeg.begin(); cItr != vecSeg.end(); ++cItr) { cout << *cItr << " "; } cout << endl; return 0;}void SegmentSentence(const string& sSen, const set
& oDict, int nMaxWordLen, vector
& vecWords){ // 遍历每一个字节(不是汉字) for (string::const_iterator cItr = sSen.begin(); cItr < sSen.end();) { int nWordLen = (cItr + nMaxWordLen) <= sSen.end() ? nMaxWordLen : (sSen.end() - cItr); while (nWordLen > 1) { string sWord(cItr, cItr + nWordLen); if (oDict.find(sWord) != oDict.end()) { // 字典中找到此对象 vecWords.push_back(sWord); break; } else { nWordLen -= 1; // 这个地方可以根据GBK编码规则优化 } } // 跟新当前索引 if (nWordLen == 1 && GBK_HB_MIN <= static_cast
(*cItr)) { // 添加当前的单个汉字,gbk由两个byte组成 vecWords.push_back(string(cItr, cItr + 2)); cItr += 2; } else if (nWordLen == 1 && GBK_HB_MIN > static_cast
(*cItr)) { // 添加当前的ascii码 vecWords.push_back(string(1, *cItr)); cItr += 1; } else { cItr += nWordLen; } }}void LoadDictionary(const string& sDictPath, set
& oDict, int& nMaxWordLen) { // 加载字典 ifstream oReader(sDictPath.c_str()); if (!oReader.is_open()) { cout << "Fail to open file : " << DICT_PATH << endl; exit(0); } string sLine; nMaxWordLen = 0; while (getline(oReader, sLine)) { //cout << "Current Line :" << sLine << endl; // debug /** * 字典的每一行格式为: * ID SP 词语 SP 频率 * * 只有两个空格(SP)之间的词语需要添加到本字典中 */ // 达到第一个空格 int nSpOffset = 0; for (string::const_iterator cItr = sLine.begin(); cItr != sLine.end(); ++cItr, ++ nSpOffset) { if (SP == *cItr) { break; } } // 读取词语 string sWord(""); for (string::const_iterator cItr = sLine.begin() + nSpOffset + 1; cItr != sLine.end(); ++cItr) { if (SP == *cItr) { // 遇到第二个空格,断开 break; } sWord.append(1, *cItr); if (GBK_HB_MIN <= static_cast
(*cItr)) { // 针对GBK编码特殊处理,避免截断词语 ++ cItr; if (cItr != sLine.end()) { sWord.append(1, *cItr); } else { cout << "line format error: '" << sLine << "'" << endl; exit(0); } } } // 将此与添加到字典中 if ("" != sWord) { if (!oDict.insert(sWord).second) { cout << "Word conflict: " << sWord << endl; exit(0); } } // 比较最长字长 if (nMaxWordLen < sWord.size()) { nMaxWordLen = sWord.size(); } } oReader.close();}

转载地址:http://ehfvx.baihongyu.com/

你可能感兴趣的文章
CodeIgniter的密码处理论
查看>>
运营不需要人脉?
查看>>
Spring Cloud Config服务器
查看>>
测试人员必学的软件快速测试方法(二)
查看>>
Agora iOS SDK-快速入门
查看>>
[STM32F429-DISCO-uCosiii]3.uCOSIII 移植
查看>>
LeetCode | Copy List with Random Pointer
查看>>
C语言博客05--指针
查看>>
Windows平台下,Scrapy Installation,安装问题解决
查看>>
引入间接隔离变化(三)
查看>>
统一沟通-技巧-4-让国内域名提供商“提供”SRV记录
查看>>
cocos2d-x 3.0事件机制及用户输入
查看>>
FUHLEN/富勒 U79/U79G节能系列/U系列无线2.4G接收器-淘宝网
查看>>
比亚迪速锐F3专用夏季座套 夏天坐垫 四季坐套
查看>>
C++ 数字转换为string类型
查看>>
取证学习资料DVD
查看>>
高性能优化Web前端
查看>>
Sublime Text 格式化代码快捷键
查看>>
疯狂的 Web 应用开源项目
查看>>
hdu 4775 Infinite Go(暴力)
查看>>