使用C++实现mmseg,对中文句子进行分词(一)

2014-11-24 12:17:24 · 作者: · 浏览: 7

这里我的这段代码为了实现的简单化,假设传进来的参数都是中文字符串,也就是不含有字母数字类似的东西。


例如 string test="研究生命起源";
分词效果为 : 研究 生命 起源,还算正确。
初始化过程中,有很多文件读取的操作,其中有一个文件存储了我们需要的词库,另外还有一个词频的文件。
主要的算法采用递归来实现,主要是考虑到实现的方便性,大家如果觉得实在受不了递归,可以考虑修改出一个非递归的版本。采用递归的方法实现,于是就导致了当一个串很长很长的时候需要很长的时间才能做好分词,似乎,已经慢的快到了不能忍的地步了。时间复杂度接近2^n,n为字符串的中文字的个数。

PS:在Ubuntu下的eclipse编译通过的代码,这里一个中文字是三个字节,如果在windows下Visual Studio,是两个字节,这个我在开头通过测试一个字符串的长度来获取,这样用稍微变通的方法让这个可以在不同平台直接使用。

代码见附件。里面有词库加上代码。

[cpp]
/*
* buildTerms.cpp
*
* Created on: Dec 21, 2011
* Author: lai_conglin
*/

# include
# include
# include
# include
# include
# include
# include
# include
#include
using namespace std;
map > content;
map freq;
size_t ChineseLength;
void initial(){
string testch="测试";
// cout< ChineseLength=testch.length()/2;
}
struct Word {
private:
string value;
int frequence;
public:
Word() {

}
void setValue(string src) {
value = src;
/**
* a single character will need to find its frequence , and a term will be 1 default
*/
if (value.length() == ChineseLength) {
map::iterator it = freq.find(value);
if (it == freq.end()) {
frequence = 1;
} else {
frequence = freq[value];
}
} else {
frequence = 1;
}
}
string getValue() {
return value;
}
int getLength() {
return value.length();
}
int getFrequency() {
return frequence;
}
};
struct Chunk {
public:
vector list;

Chunk() {

}
/**
* add a word to the list
*/
void addWord(Word w) {
list.push_back(w);
}
int getWordNumber() {
return list.size();
}
double getVariance() {
double avgLen = 0.0;
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
avgLen += list.at(i).getLength();
}
avgLen = 1.0 * avgLen / listSize;
double variance = 1.0;
for (int i = 0; i < listSize; i++) {
double temp = (avgLen - list.at(i).getLength());
variance += temp * temp;
}
return variance;
}
long getFreq() {
long freqValue = 0;
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
freqValue += list.at(i).getFrequency();
}
return freqValue;
}
vector getVectorString() {
vector res;
int size = list.size();
for (int i = 0; i < size; i++) {
res.push_back(list.at(i).getValue());
}
return res;
}
};
void read_terms_from_Lexicon() {
ifstream fin("Lexicon_full_words.txt");
// string test="一·二八";
// cout< string dot = "·";
// cout< string s;
string temp;
map >::iterator lexiconIterator;
s.clear();
//ignore the first one string, I don't know why
fin >> s;
cout << "start read from Lexicon_full_words.txt" << endl;
cout << "reading terms: -> " << endl;

while (fin >> s) {
// int len = s.length();
set tempSet;
//one character will cost 3 bytes in linux, 2 in windows....maybe not right.you need to test it
temp.clear();
temp = s.substr(0, ChineseLength);
lexiconIterator = content.find(temp);
if (lexiconIterator == content.end()) {
tempSet.clear();
tempSet.insert(s);
} else {
tempSet = content[temp];
tempSet.insert(s);
}
content[temp