文本挖掘模型:本特征提取文本挖掘模型结构示意图1. 分词分词实例:提高人民生活水平:提高、高人、人民、民生、生活、活水、水平分词基本方法:最大匹配法、最大概率法分词、最短路径分词方法1.1 最大匹配法中文分词在中文信息处理中是最最基础的,无论机器翻译亦或信息检索还是其他相关应用,如果涉及中文,都离不开中文分词,因此中文分词具有极高的地位。
正向最大匹配法算法如下图:实例:S1="计算语言学课程是三个课时",设定最大词长MaxLen= 5,S2= " "(1)S2=“”;S1不为空,从S1左边取出候选子串W="计算语言学";(2)查词表,“计算语言学”在词表中,将W加入到S2中,S2=“计算语言学/ ”,并将W从S1中去掉,此时S1="课程是三个课时";(3)S1不为空,于是从S1左边取出候选子串W="课程是三个";(4)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程是三";(5)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程是";(6)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程"(7)查词表,W在词表中,将W加入到S2中,S2=“计算语言学/ 课程/ ”,并将W从S1中去掉,此时S1="是三个课时";(8)S1不为空,于是从S1左边取出候选子串W="是三个课时";(9)查词表,W不在词表中,将W最右边一个字去掉,得到W="是三个课";(10)查词表,W不在词表中,将W最右边一个字去掉,得到W="是三个";(11)查词表,W不在词表中,将W最右边一个字去掉,得到W="是三"(12)查词表,W不在词表中,将W最右边一个字去掉,得到W=“是”,这时W是单字,将W加入到S2中,S2=“计算语言学/ 课程/ 是/ ”,并将W从S1中去掉,此时S1="三个课时";。
(21)S2=“计算语言学/ 课程/ 是/ 三/ 个/ 课时/ ”,此时S1=""。
(22)S1为空,输出S2作为分词结果,分词过程结束。
代码如下:[cpp]view plaincopy1.#include <iostream>2.#include <string>3.#include <fstream>4.#include <sstream>5.#include <hash_map>ing namespace std;ing namespace stdext;8.9.class CDictionary10.{11.public:12. CDictionary(); //将词典文件读入并构造为一个哈希词典13. ~CDictionary();14.int FindWord(string w); //在哈希词典中查找词15.private:16. string strtmp; //读取词典的每一行17. string word; //保存每个词18. hash_map<string, int> wordhash; // 用于读取词典后的哈希19. hash_map<string, int >::iterator worditer; //20.typedef pair<string, int> sipair;21.};22.23.//将词典文件读入并构造为一个哈希词典24.CDictionary::CDictionary()25.{26. ifstream infile("wordlexicon"); // 打开词典27.if (!infile.is_open()) // 打开词典失败则退出程序28. {29. cerr << "Unable to open input file: " << "wordlexicon"30. << " -- bailing out!" << endl;31. exit(-1);32. }33.while (getline(infile, strtmp, 'n')) // 读入词典的每一行并将其添加入哈希中34. {35. istringstream istr(strtmp);36. istr >> word; //读入每行第一个词37. wordhash.insert(sipair(word, 1)); //插入到哈希中38. }39.}40.41.CDictionary::~CDictionary()42.{43.}44.45.//在哈希词典中查找词,若找到,则返回,否则返回46.int CDictionary::FindWord(string w)47.{48.if (wordhash.find(w) != wordhash.end())49. {50.return 1;51. }52.else53. {54.return 0;55. }56.}57.58.#define MaxWordLength 10 // 最大词长为个字节(即个汉字)59.#define Separator "/ " // 词界标记60.61.CDictionary WordDic; //初始化一个词典62.63.//对字符串用最大匹配法(正向或逆向)处理64.string SegmentSentence(string s1)65.{66. string s2 = ""; //用s2存放分词结果67.while(!s1.empty())68. {69.int len =(int) s1.length(); // 取输入串长度70.if (len > MaxWordLength) // 如果输入串长度大于最大词长71. {72. len = MaxWordLength; // 只在最大词长范围内进行处理73. }74.//string w = s1.substr(0, len); // (正向用)将输入串左边等于最大词长长度串取出作为候选词75. string w = s1.substr(s1.length() - len, len); //逆向用76.int n = WordDic.FindWord(w); // 在词典中查找相应的词77.while(len > 2 && n == 0) // 如果不是词78. {79. len -= 2; // 从候选词右边减掉一个汉字,将剩下的部分作为候选词80.//w = w.substr(0, len); //正向用81. w = s1.substr(s1.length() - len, len); //逆向用82. n = WordDic.FindWord(w);83. }84.//s2 += w + Separator; // (正向用)将匹配得到的词连同词界标记加到输出串末尾85. w = w + Separator; // (逆向用)86. s2 = w + s2 ; // (逆向用)87.//s1 = s1.substr(w.length(), s1.length()); //(正向用)从s1-w处开始88. s1 = s1.substr(0, s1.length() - len); // (逆向用)89. }90.return s2;91.}92.93.//对句子进行最大匹配法处理,包含对特殊字符的处理94.string SegmentSentenceMM (string s1)95.{96. string s2 = ""; //用s2存放分词结果97.int i;98.int dd;99.while(!s1.empty() )100. {101. unsigned char ch = (unsigned char)s1[0];102.if (ch < 128) // 处理西文字符103. {104. i = 1;105. dd = (int)s1.length();106.while (i < dd && ((unsigned char)s1[i] < 128) && (s1[i] != 10) && (s1[i] != 13)) // s1[i]不能是换行符或回车符107. {108. i++;109. }110.if ((ch != 32) && (ch != 10) && (ch != 13)) // 如果不是西文空格或换行或回车符111. {112. s2 += s1.substr(0,i) + Separator;113. }114.else115. {116.//if (ch == 10 || ch == 13) // 如果是换行或回车符,将它拷贝给s2输出117.if (ch == 10 || ch == 13 || ch == 32) //谢谢读者mces89的指正118. {119. s2 += s1.substr(0, i);120. }121. }122. s1 = s1.substr(i,dd);123.continue;124. }125.else126. {127.if (ch < 176) // 中文标点等非汉字字符128. {129. i = 0;130. dd = (int)s1.length();131.while(i < dd && ((unsigned char)s1[i] < 176) && ((unsigned char)s1[i] >= 161)132. && (!((unsigned char)s1[i] == 161 && ((unsigned char)s1 [i+1] >= 162 && (unsigned char)s1[i+1] <= 168)))133. && (!((unsigned char)s1[i] == 161 && ((unsigned char)s1 [i+1] >= 171 && (unsigned char)s1[i+1] <= 191)))134. && (!((unsigned char)s1[i] == 163 && ((unsigned char)s1 [i+1] == 172 || (unsigned char)s1[i+1] == 161)135. || (unsigned char)s1[i+1] == 168 || (unsigned char)s1[i +1] == 169 || (unsigned char)s1[i+1] == 186136. || (unsigned char)s1[i+1] == 187 || (unsigned char)s1[i +1] == 191)))137. {138. i = i + 2; // 假定没有半个汉字139. }140.if (i == 0)141. {142. i = i + 2;143. }144.if (!(ch == 161 && (unsigned char)s1[1] == 161)) // 不处理中文空格145. {146. s2+=s1.substr(0, i) + Separator; // 其他的非汉字双字节字符可能连续输出147. }148. s1 = s1.substr(i, dd);149.continue;150. }151. }152.// 以下处理汉字串153. i = 2;154. dd = (int)s1.length();155.while(i < dd && (unsigned char)s1[i] >= 176)156. {157. i += 2;158. }159. s2 += SegmentSentence(s1.substr(0, i));160. s1 = s1.substr(i,dd);161. }162.return s2;163.}164.165.int main(int argc, char *argv[])166.{167. string strtmp; //用于保存从语料库中读入的每一行168. string line; //用于输出每一行的结果169. ifstream infile(argv[1]); // 打开输入文件170.if (!infile.is_open()) // 打开输入文件失败则退出程序171. {172. cerr << "Unable to open input file: " << argv[1]173. << " -- bailing out!" << endl;174. exit(-1);175. }176. ofstream outfile1("SegmentResult.txt"); //确定输出文件177.if (!outfile1.is_open())178. {179. cerr << "Unable to open file:SegmentResult.txt"180. << "--bailing out!" << endl;181. exit(-1);182. }183.while (getline(infile, strtmp, 'n')) //读入语料库中的每一行并用最大匹配法处理184. {185. line = strtmp;186. line = SegmentSentenceMM(line); // 调用分词函数进行分词处理187. outfile1 << line << endl; // 将分词结果写入目标文件188. }189.return 0;190.}其它基于匹配的分词方法:最大匹配法(Maximum Matching method):匹配的方向是从左向右。