自动提取文章摘要AutoSummary
在文本搜索引擎项目中,需要对已排序的文章进行摘要提取,然后与标题,路径一起封装成Json数据返回客户端。因此这里我自己写一个自动摘要,来大概完成这个任务。在自动摘要提取过程中,使用了一个分词库:CppJieba分词库。因此在头文件中包含了头文件 “Application.hpp”。
思路:
1、对文章提取关键字。通常,关键字能够代表这篇文章的所描述的内容。因此使用CppJieba分词库中“Application.hpp”中api extract()进行关键字提取。我提取的是前50个,若文章关键字不够50个则取实际个数。关键字的结果已经按照权重的顺序排序好。
2、把文章拆分成句子。这里是只对中文进行处理(英文道理也一样),当遇到句号‘ 。’,问号‘ ? ’,感叹号‘ ! ’,算一句话。把每一句话按顺序保存到vector<string>类型的数组sentences中。
3、遍历关键字数组,对每一个关键字在每一个句子中查找包含该关键字的第一个句子,并把该句子加入到vector<string>类型的数组summary中。
4、若遍历到达关键字上限或者句子数量到达上限,跳出循环。
5、将数组summary中的句子按顺序拼接从摘要。
代码如下:
1 #ifndef _AUTOSUMMERY_HPP 2 #define _AUTOSUMMERY_HPP 3 #include"../src/Statistics/src/Application.hpp" 4 #include <string> 5 #include<set> 6 #include <utility> 7 #include<vector> 8 #include<iostream> 9 #include<functional> 10 using namespace std; 11 using namespace CppJieba; 12 class AutoSummary 13 { 14 public: 15 AutoSummary(Application &app,int maxSentenceNum=10)//初始化一个自动摘要对象 16 :maxSentenceNum_(maxSentenceNum), 17 app_(app) 18 {} 19 20 //自动提取摘要 21 string summarizer(string & originTxt,int KEYNUM=50) 22 { 23 vector<pair<string,double> > keywords; 24 app_.extract(originTxt,keywords,KEYNUM); //取文章的前50个关键词,按权重排序 25 vector<string> sentences; //装载句子的数组 26 getSentences(originTxt,sentences); //把文章拆分成句子 27 int sentencesNum = sentences.size(); //句子的数量 28 vector<string> summaryRet; //装包含关键字的句子 29 set<int> summarySet; //句子去重 30 set<int>::iterator it; 31 KEYNUM = keywords.size();//如果关键字数量小于50则取实际的数量 32 for(int i = 0;i<KEYNUM;i++) 33 { 34 for(int j = 0;j<sentencesNum;j++) 35 { 36 int pos = sentences[j].find(keywords[i].first,0); 37 if(pos!=string::npos) 38 { 39 it = summarySet.find(pos); 40 if(it==summarySet.end()) 41 { 42 summaryRet.push_back(sentences[j]);//向数组添加句子 43 summarySet.insert(j); 44 break; //跳出循环,找下一个关键字 45 } 46 } 47 } 48 //跳出循环的条件 49 if(summaryRet.size()>maxSentenceNum_||summaryRet.size()>=sentencesNum) 50 break; 51 } 52 string summaryStr; 53 int i = 0; 54 int num = summaryRet.size(); 55 while(i<num) 56 { 57 summaryStr = summaryStr + sentences[i]+"……"; 58 i++; 59 } 60 61 return summaryStr; 62 } 63 64 private: 65 //将文章拆分成句子,私有成员函数,在summarizer()中调用 66 void getSentences(const string &originTxt,vector<string> &sentenceVec) 67 { 68 int beg=0,end=0,pos=0,pos1=0; 69 int txtSize = originTxt.size(); 70 while(beg<txtSize&&pos!=string::npos) 71 { 72 if((pos=originTxt.find("。",beg))!=string::npos) 73 { 74 if((pos1=originTxt.find("?",beg))!=string::npos) 75 { 76 pos=((pos<pos1)?pos:pos1); 77 if((pos1=originTxt.find("!",beg))!=string::npos) 78 { 79 pos=((pos<pos1)?pos:pos1); 80 } 81 82 } 83 else if((pos1=originTxt.find("!",beg))!=string::npos) 84 { 85 pos=((pos<pos1)?pos:pos1); 86 } 87 } 88 else if((pos=originTxt.find("?",beg))!=string::npos) 89 { 90 if((pos1=originTxt.find("!",beg))!=string::npos) 91 { 92 pos=((pos<pos1)?pos:pos1); 93 } 94 95 } 96 else if((pos1=originTxt.find("!",beg))!=string::npos) 97 { 98 pos = pos1; 99 } 100 else 101 { 102 break; 103 } 104 if(pos!=-1) 105 { 106 int len = pos-beg; 107 string sentence(originTxt.substr(beg,len)); 108 sentenceVec.push_back(sentence); 109 beg = pos+3; 110 } 111 } 112 } 113 114 private: 115 Application & app_;//分词库的引用 116 int maxSentenceNum_;//摘要中的句子数目,由外部传进。 117 }; 118 #endif
参考:http://www.ruanyifeng.com/blog/2013/03/automatic_summarization.html
手与大脑的距离决定了理想与现实的相似度