mirror of
https://github.com/yanyiwu/cppjieba.git
synced 2025-07-18 00:00:12 +08:00
Merge remote-tracking branch 'origin/hpp_ing' into dev
This commit is contained in:
commit
bdb645ce69
@ -1,23 +1,15 @@
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
|
||||
|
||||
SET(LIBCPPJIEBA_SRC HMMSegment.cpp MixSegment.cpp MPSegment.cpp Trie.cpp)
|
||||
ADD_LIBRARY(cppjieba STATIC ${LIBCPPJIEBA_SRC})
|
||||
ADD_EXECUTABLE(cjsegment segment.cpp)
|
||||
ADD_EXECUTABLE(cjserver server.cpp)
|
||||
TARGET_LINK_LIBRARIES(cjserver husky pthread)
|
||||
|
||||
LINK_DIRECTORIES(Husky)
|
||||
|
||||
TARGET_LINK_LIBRARIES(cjsegment cppjieba)
|
||||
TARGET_LINK_LIBRARIES(cjserver cppjieba husky pthread)
|
||||
|
||||
SET_TARGET_PROPERTIES(cppjieba PROPERTIES VERSION 1.2 SOVERSION 1)
|
||||
|
||||
INSTALL(TARGETS cjsegment RUNTIME DESTINATION bin)
|
||||
INSTALL(TARGETS cjserver RUNTIME DESTINATION bin)
|
||||
INSTALL(TARGETS cppjieba ARCHIVE DESTINATION lib/CppJieba)
|
||||
INSTALL(FILES ChineseFilter.hpp HMMSegment.h MPSegment.h structs.h Trie.h globals.h ISegment.hpp MixSegment.h SegmentBase.hpp TransCode.hpp DESTINATION include/CppJieba)
|
||||
|
||||
INSTALL(FILES ChineseFilter.hpp HMMSegment.hpp MPSegment.hpp Trie.hpp ISegment.hpp MixSegment.hpp SegmentBase.hpp TransCode.hpp DESTINATION include/CppJieba)
|
||||
|
||||
ADD_SUBDIRECTORY(Husky)
|
||||
ADD_SUBDIRECTORY(Limonp)
|
||||
|
@ -1,14 +1,14 @@
|
||||
#ifndef CPPJIEBA_CHINESEFILTER_H
|
||||
#define CPPJIEBA_CHINESEFILTER_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "TransCode.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
enum CHAR_TYPE { CHWORD = 0, DIGIT_OR_LETTER = 1, OTHERS = 2};
|
||||
typedef Unicode::const_iterator UniConIter;
|
||||
class ChineseFilter;
|
||||
|
||||
class ChFilterIterator
|
||||
{
|
||||
public:
|
||||
|
@ -1,341 +0,0 @@
|
||||
#include "HMMSegment.h"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
HMMSegment::HMMSegment()
|
||||
{
|
||||
memset(_startProb, 0, sizeof(_startProb));
|
||||
memset(_transProb, 0, sizeof(_transProb));
|
||||
_statMap[0] = 'B';
|
||||
_statMap[1] = 'E';
|
||||
_statMap[2] = 'M';
|
||||
_statMap[3] = 'S';
|
||||
_emitProbVec.push_back(&_emitProbB);
|
||||
_emitProbVec.push_back(&_emitProbE);
|
||||
_emitProbVec.push_back(&_emitProbM);
|
||||
_emitProbVec.push_back(&_emitProbS);
|
||||
}
|
||||
|
||||
HMMSegment::~HMMSegment()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
bool HMMSegment::init(const char* const modelPath)
|
||||
{
|
||||
return _setInitFlag(_loadModel(modelPath));
|
||||
}
|
||||
|
||||
bool HMMSegment::dispose()
|
||||
{
|
||||
_setInitFlag(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMMSegment::_loadModel(const char* const filePath)
|
||||
{
|
||||
LogInfo("loadModel [%s] start ...", filePath);
|
||||
ifstream ifile(filePath);
|
||||
string line;
|
||||
vector<string> tmp;
|
||||
vector<string> tmp2;
|
||||
//load _startProb
|
||||
if(!_getLine(ifile, line))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
splitStr(line, tmp, " ");
|
||||
if(tmp.size() != STATUS_SUM)
|
||||
{
|
||||
LogError("start_p illegal");
|
||||
return false;
|
||||
}
|
||||
for(uint j = 0; j< tmp.size(); j++)
|
||||
{
|
||||
_startProb[j] = atof(tmp[j].c_str());
|
||||
//cout<<_startProb[j]<<endl;
|
||||
}
|
||||
|
||||
//load _transProb
|
||||
for(uint i = 0; i < STATUS_SUM; i++)
|
||||
{
|
||||
if(!_getLine(ifile, line))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
splitStr(line, tmp, " ");
|
||||
if(tmp.size() != STATUS_SUM)
|
||||
{
|
||||
LogError("trans_p illegal");
|
||||
return false;
|
||||
}
|
||||
for(uint j =0; j < STATUS_SUM; j++)
|
||||
{
|
||||
_transProb[i][j] = atof(tmp[j].c_str());
|
||||
//cout<<_transProb[i][j]<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
//load _emitProbB
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbB))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//load _emitProbE
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//load _emitProbM
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbM))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//load _emitProbS
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo("loadModel [%s] end.", filePath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMMSegment::cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<Unicode>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
vector<uint> status;
|
||||
if(!_viterbi(begin, end, status))
|
||||
{
|
||||
LogError("_viterbi failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Unicode::const_iterator left = begin;
|
||||
Unicode::const_iterator right;
|
||||
for(uint i =0; i< status.size(); i++)
|
||||
{
|
||||
if(status[i] % 2) //if(E == status[i] || S == status[i])
|
||||
{
|
||||
right = begin + i + 1;
|
||||
res.push_back(Unicode(left, right));
|
||||
left = right;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMMSegment::cut(const string& str, vector<string>& res)const
|
||||
{
|
||||
return SegmentBase::cut(str, res);
|
||||
}
|
||||
|
||||
bool HMMSegment::cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res) const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
if(begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vector<Unicode> words;
|
||||
if(!cut(begin, end, words))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string tmp;
|
||||
for(uint i = 0; i < words.size(); i++)
|
||||
{
|
||||
if(TransCode::encode(words[i], tmp))
|
||||
{
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMMSegment::_viterbi(Unicode::const_iterator begin, Unicode::const_iterator end, vector<uint>& status)const
|
||||
{
|
||||
if(begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t Y = STATUS_SUM;
|
||||
size_t X = end - begin;
|
||||
size_t XYSize = X * Y;
|
||||
int * path;
|
||||
double * weight;
|
||||
uint now, old, stat;
|
||||
double tmp, endE, endS;
|
||||
|
||||
try
|
||||
{
|
||||
path = new int [XYSize];
|
||||
weight = new double [XYSize];
|
||||
}
|
||||
catch(const std::bad_alloc&)
|
||||
{
|
||||
LogError("bad_alloc");
|
||||
return false;
|
||||
}
|
||||
if(NULL == path || NULL == weight)
|
||||
{
|
||||
LogError("bad_alloc");
|
||||
return false;
|
||||
}
|
||||
|
||||
//start
|
||||
for(uint y = 0; y < Y; y++)
|
||||
{
|
||||
weight[0 + y * X] = _startProb[y] + _getEmitProb(_emitProbVec[y], *begin, MIN_DOUBLE);
|
||||
path[0 + y * X] = -1;
|
||||
}
|
||||
//process
|
||||
//for(; begin != end; begin++)
|
||||
for(uint x = 1; x < X; x++)
|
||||
{
|
||||
for(uint y = 0; y < Y; y++)
|
||||
{
|
||||
now = x + y*X;
|
||||
weight[now] = MIN_DOUBLE;
|
||||
path[now] = E; // warning
|
||||
for(uint preY = 0; preY < Y; preY++)
|
||||
{
|
||||
old = x - 1 + preY * X;
|
||||
tmp = weight[old] + _transProb[preY][y] + _getEmitProb(_emitProbVec[y], *(begin+x), MIN_DOUBLE);
|
||||
if(tmp > weight[now])
|
||||
{
|
||||
weight[now] = tmp;
|
||||
path[now] = preY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endE = weight[X-1+E*X];
|
||||
endS = weight[X-1+S*X];
|
||||
stat = 0;
|
||||
if(endE > endS)
|
||||
{
|
||||
stat = E;
|
||||
}
|
||||
else
|
||||
{
|
||||
stat = S;
|
||||
}
|
||||
|
||||
status.assign(X, 0);
|
||||
for(int x = X -1 ; x >= 0; x--)
|
||||
{
|
||||
status[x] = stat;
|
||||
stat = path[x + stat*X];
|
||||
}
|
||||
|
||||
delete [] path;
|
||||
delete [] weight;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMMSegment::_getLine(ifstream& ifile, string& line)
|
||||
{
|
||||
while(getline(ifile, line))
|
||||
{
|
||||
trim(line);
|
||||
if(line.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(strStartsWith(line, "#"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HMMSegment::_loadEmitProb(const string& line, EmitProbMap& mp)
|
||||
{
|
||||
if(line.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vector<string> tmp, tmp2;
|
||||
uint16_t unico = 0;
|
||||
splitStr(line, tmp, ",");
|
||||
for(uint i = 0; i < tmp.size(); i++)
|
||||
{
|
||||
splitStr(tmp[i], tmp2, ":");
|
||||
if(2 != tmp2.size())
|
||||
{
|
||||
LogError("_emitProb illegal.");
|
||||
return false;
|
||||
}
|
||||
if(!_decodeOne(tmp2[0], unico))
|
||||
{
|
||||
LogError("TransCode failed.");
|
||||
return false;
|
||||
}
|
||||
mp[unico] = atof(tmp2[1].c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMMSegment::_decodeOne(const string& str, uint16_t& res)
|
||||
{
|
||||
Unicode ui16;
|
||||
if(!TransCode::decode(str, ui16) || ui16.size() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
res = ui16[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
double HMMSegment::_getEmitProb(const EmitProbMap* ptMp, uint16_t key, double defVal)const
|
||||
{
|
||||
EmitProbMap::const_iterator cit = ptMp->find(key);
|
||||
if(cit == ptMp->end())
|
||||
{
|
||||
return defVal;
|
||||
}
|
||||
return cit->second;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HMMSEGMENT_UT
|
||||
using namespace CppJieba;
|
||||
|
||||
|
||||
size_t add(size_t a, size_t b)
|
||||
{
|
||||
return a*b;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
TransCode::setUtf8Enc();
|
||||
HMMSegment hmm;
|
||||
hmm.loadModel("../dicts/hmm_model.utf8");
|
||||
vector<string> res;
|
||||
hmm.cut("小明硕士毕业于北邮网络研究院。。.", res);
|
||||
cout<<joinStr(res, "/")<<endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,59 +0,0 @@
|
||||
#ifndef CPPJIBEA_HMMSEGMENT_H
|
||||
#define CPPJIBEA_HMMSEGMENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory.h>
|
||||
#include "Limonp/str_functs.hpp"
|
||||
#include "Limonp/logger.hpp"
|
||||
#include "globals.h"
|
||||
#include "TransCode.hpp"
|
||||
#include "ISegment.hpp"
|
||||
#include "SegmentBase.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
using namespace Limonp;
|
||||
class HMMSegment: public SegmentBase
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* STATUS:
|
||||
* 0:B, 1:E, 2:M, 3:S
|
||||
* */
|
||||
enum {B = 0, E = 1, M = 2, S = 3, STATUS_SUM = 4};
|
||||
private:
|
||||
char _statMap[STATUS_SUM];
|
||||
double _startProb[STATUS_SUM];
|
||||
double _transProb[STATUS_SUM][STATUS_SUM];
|
||||
EmitProbMap _emitProbB;
|
||||
EmitProbMap _emitProbE;
|
||||
EmitProbMap _emitProbM;
|
||||
EmitProbMap _emitProbS;
|
||||
vector<EmitProbMap* > _emitProbVec;
|
||||
|
||||
public:
|
||||
HMMSegment();
|
||||
virtual ~HMMSegment();
|
||||
public:
|
||||
bool init(const char* const modelPath);
|
||||
bool dispose();
|
||||
public:
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<Unicode>& res)const ;
|
||||
bool cut(const string& str, vector<string>& res)const;
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const;
|
||||
//virtual bool cut(const string& str, vector<string>& res)const;
|
||||
|
||||
private:
|
||||
bool _viterbi(Unicode::const_iterator begin, Unicode::const_iterator end, vector<uint>& status)const;
|
||||
bool _loadModel(const char* const filePath);
|
||||
bool _getLine(ifstream& ifile, string& line);
|
||||
bool _loadEmitProb(const string& line, EmitProbMap& mp);
|
||||
bool _decodeOne(const string& str, uint16_t& res);
|
||||
double _getEmitProb(const EmitProbMap* ptMp, uint16_t key, double defVal)const ;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
346
src/HMMSegment.hpp
Normal file
346
src/HMMSegment.hpp
Normal file
@ -0,0 +1,346 @@
|
||||
#ifndef CPPJIBEA_HMMSEGMENT_H
|
||||
#define CPPJIBEA_HMMSEGMENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory.h>
|
||||
#include "Limonp/str_functs.hpp"
|
||||
#include "Limonp/logger.hpp"
|
||||
#include "TransCode.hpp"
|
||||
#include "ISegment.hpp"
|
||||
#include "SegmentBase.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
using namespace Limonp;
|
||||
typedef unordered_map<uint16_t, double> EmitProbMap;
|
||||
class HMMSegment: public SegmentBase
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* STATUS:
|
||||
* 0:B, 1:E, 2:M, 3:S
|
||||
* */
|
||||
enum {B = 0, E = 1, M = 2, S = 3, STATUS_SUM = 4};
|
||||
private:
|
||||
char _statMap[STATUS_SUM];
|
||||
double _startProb[STATUS_SUM];
|
||||
double _transProb[STATUS_SUM][STATUS_SUM];
|
||||
EmitProbMap _emitProbB;
|
||||
EmitProbMap _emitProbE;
|
||||
EmitProbMap _emitProbM;
|
||||
EmitProbMap _emitProbS;
|
||||
vector<EmitProbMap* > _emitProbVec;
|
||||
|
||||
public:
|
||||
HMMSegment()
|
||||
{
|
||||
memset(_startProb, 0, sizeof(_startProb));
|
||||
memset(_transProb, 0, sizeof(_transProb));
|
||||
_statMap[0] = 'B';
|
||||
_statMap[1] = 'E';
|
||||
_statMap[2] = 'M';
|
||||
_statMap[3] = 'S';
|
||||
_emitProbVec.push_back(&_emitProbB);
|
||||
_emitProbVec.push_back(&_emitProbE);
|
||||
_emitProbVec.push_back(&_emitProbM);
|
||||
_emitProbVec.push_back(&_emitProbS);
|
||||
}
|
||||
virtual ~HMMSegment()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
public:
|
||||
bool init(const char* const modelPath)
|
||||
{
|
||||
return _setInitFlag(_loadModel(modelPath));
|
||||
}
|
||||
bool dispose()
|
||||
{
|
||||
_setInitFlag(false);
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<Unicode>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
vector<uint> status;
|
||||
if(!_viterbi(begin, end, status))
|
||||
{
|
||||
LogError("_viterbi failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Unicode::const_iterator left = begin;
|
||||
Unicode::const_iterator right;
|
||||
for(uint i =0; i< status.size(); i++)
|
||||
{
|
||||
if(status[i] % 2) //if(E == status[i] || S == status[i])
|
||||
{
|
||||
right = begin + i + 1;
|
||||
res.push_back(Unicode(left, right));
|
||||
left = right;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool cut(const string& str, vector<string>& res)const
|
||||
{
|
||||
return SegmentBase::cut(str, res);
|
||||
}
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
if(begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vector<Unicode> words;
|
||||
if(!cut(begin, end, words))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string tmp;
|
||||
for(uint i = 0; i < words.size(); i++)
|
||||
{
|
||||
if(TransCode::encode(words[i], tmp))
|
||||
{
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//virtual bool cut(const string& str, vector<string>& res)const;
|
||||
|
||||
private:
|
||||
bool _viterbi(Unicode::const_iterator begin, Unicode::const_iterator end, vector<uint>& status)const
|
||||
{
|
||||
if(begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t Y = STATUS_SUM;
|
||||
size_t X = end - begin;
|
||||
size_t XYSize = X * Y;
|
||||
int * path;
|
||||
double * weight;
|
||||
uint now, old, stat;
|
||||
double tmp, endE, endS;
|
||||
|
||||
try
|
||||
{
|
||||
path = new int [XYSize];
|
||||
weight = new double [XYSize];
|
||||
}
|
||||
catch(const std::bad_alloc&)
|
||||
{
|
||||
LogError("bad_alloc");
|
||||
return false;
|
||||
}
|
||||
if(NULL == path || NULL == weight)
|
||||
{
|
||||
LogError("bad_alloc");
|
||||
return false;
|
||||
}
|
||||
|
||||
//start
|
||||
for(uint y = 0; y < Y; y++)
|
||||
{
|
||||
weight[0 + y * X] = _startProb[y] + _getEmitProb(_emitProbVec[y], *begin, MIN_DOUBLE);
|
||||
path[0 + y * X] = -1;
|
||||
}
|
||||
//process
|
||||
//for(; begin != end; begin++)
|
||||
for(uint x = 1; x < X; x++)
|
||||
{
|
||||
for(uint y = 0; y < Y; y++)
|
||||
{
|
||||
now = x + y*X;
|
||||
weight[now] = MIN_DOUBLE;
|
||||
path[now] = E; // warning
|
||||
for(uint preY = 0; preY < Y; preY++)
|
||||
{
|
||||
old = x - 1 + preY * X;
|
||||
tmp = weight[old] + _transProb[preY][y] + _getEmitProb(_emitProbVec[y], *(begin+x), MIN_DOUBLE);
|
||||
if(tmp > weight[now])
|
||||
{
|
||||
weight[now] = tmp;
|
||||
path[now] = preY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endE = weight[X-1+E*X];
|
||||
endS = weight[X-1+S*X];
|
||||
stat = 0;
|
||||
if(endE > endS)
|
||||
{
|
||||
stat = E;
|
||||
}
|
||||
else
|
||||
{
|
||||
stat = S;
|
||||
}
|
||||
|
||||
status.assign(X, 0);
|
||||
for(int x = X -1 ; x >= 0; x--)
|
||||
{
|
||||
status[x] = stat;
|
||||
stat = path[x + stat*X];
|
||||
}
|
||||
|
||||
delete [] path;
|
||||
delete [] weight;
|
||||
return true;
|
||||
}
|
||||
bool _loadModel(const char* const filePath)
|
||||
{
|
||||
LogInfo("loadModel [%s] start ...", filePath);
|
||||
ifstream ifile(filePath);
|
||||
string line;
|
||||
vector<string> tmp;
|
||||
vector<string> tmp2;
|
||||
//load _startProb
|
||||
if(!_getLine(ifile, line))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
splitStr(line, tmp, " ");
|
||||
if(tmp.size() != STATUS_SUM)
|
||||
{
|
||||
LogError("start_p illegal");
|
||||
return false;
|
||||
}
|
||||
for(uint j = 0; j< tmp.size(); j++)
|
||||
{
|
||||
_startProb[j] = atof(tmp[j].c_str());
|
||||
//cout<<_startProb[j]<<endl;
|
||||
}
|
||||
|
||||
//load _transProb
|
||||
for(uint i = 0; i < STATUS_SUM; i++)
|
||||
{
|
||||
if(!_getLine(ifile, line))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
splitStr(line, tmp, " ");
|
||||
if(tmp.size() != STATUS_SUM)
|
||||
{
|
||||
LogError("trans_p illegal");
|
||||
return false;
|
||||
}
|
||||
for(uint j =0; j < STATUS_SUM; j++)
|
||||
{
|
||||
_transProb[i][j] = atof(tmp[j].c_str());
|
||||
//cout<<_transProb[i][j]<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
//load _emitProbB
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbB))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//load _emitProbE
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//load _emitProbM
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbM))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//load _emitProbS
|
||||
if(!_getLine(ifile, line) || !_loadEmitProb(line, _emitProbS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo("loadModel [%s] end.", filePath);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool _getLine(ifstream& ifile, string& line)
|
||||
{
|
||||
while(getline(ifile, line))
|
||||
{
|
||||
trim(line);
|
||||
if(line.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(strStartsWith(line, "#"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool _loadEmitProb(const string& line, EmitProbMap& mp)
|
||||
{
|
||||
if(line.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vector<string> tmp, tmp2;
|
||||
uint16_t unico = 0;
|
||||
splitStr(line, tmp, ",");
|
||||
for(uint i = 0; i < tmp.size(); i++)
|
||||
{
|
||||
splitStr(tmp[i], tmp2, ":");
|
||||
if(2 != tmp2.size())
|
||||
{
|
||||
LogError("_emitProb illegal.");
|
||||
return false;
|
||||
}
|
||||
if(!_decodeOne(tmp2[0], unico))
|
||||
{
|
||||
LogError("TransCode failed.");
|
||||
return false;
|
||||
}
|
||||
mp[unico] = atof(tmp2[1].c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool _decodeOne(const string& str, uint16_t& res)
|
||||
{
|
||||
Unicode ui16;
|
||||
if(!TransCode::decode(str, ui16) || ui16.size() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
res = ui16[0];
|
||||
return true;
|
||||
}
|
||||
double _getEmitProb(const EmitProbMap* ptMp, uint16_t key, double defVal)const
|
||||
{
|
||||
EmitProbMap::const_iterator cit = ptMp->find(key);
|
||||
if(cit == ptMp->end())
|
||||
{
|
||||
return defVal;
|
||||
}
|
||||
return cit->second;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +1,6 @@
|
||||
#ifndef CPPJIEBA_SEGMENTINTERFACE_H
|
||||
#define CPPJIEBA_SEGMENTINTERFACE_H
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
@ -1,265 +0,0 @@
|
||||
/************************************
|
||||
* file enc : AISCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#include "MPSegment.h"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
bool MPSegment::init(const char* const filePath)
|
||||
{
|
||||
if(_getInitFlag())
|
||||
{
|
||||
LogError("already inited before now.");
|
||||
return false;
|
||||
}
|
||||
if(!_trie.init())
|
||||
{
|
||||
LogError("_trie.init failed.");
|
||||
return false;
|
||||
}
|
||||
LogInfo("_trie.loadDict(%s) start...", filePath);
|
||||
if(!_trie.loadDict(filePath))
|
||||
{
|
||||
LogError("_trie.loadDict faield.");
|
||||
return false;
|
||||
}
|
||||
LogInfo("_trie.loadDict end.");
|
||||
return _setInitFlag(true);
|
||||
}
|
||||
|
||||
bool MPSegment::dispose()
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_trie.dispose();
|
||||
_setInitFlag(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MPSegment::cut(const string& str, vector<string>& res)const
|
||||
{
|
||||
return SegmentBase::cut(str, res);
|
||||
}
|
||||
|
||||
bool MPSegment::cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
vector<TrieNodeInfo> segWordInfos;
|
||||
if(!cut(begin, end, segWordInfos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string tmp;
|
||||
for(uint i = 0; i < segWordInfos.size(); i++)
|
||||
{
|
||||
if(TransCode::encode(segWordInfos[i].word, tmp))
|
||||
{
|
||||
res.push_back(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError("encode failed.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MPSegment::cut(Unicode::const_iterator begin , Unicode::const_iterator end, vector<TrieNodeInfo>& segWordInfos)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
SegmentContext segContext;
|
||||
for(Unicode::const_iterator it = begin; it != end; it++)
|
||||
{
|
||||
segContext.push_back(SegmentChar(*it));
|
||||
}
|
||||
|
||||
//calc DAG
|
||||
if(!_calcDAG(segContext))
|
||||
{
|
||||
LogError("_calcDAG failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!_calcDP(segContext))
|
||||
{
|
||||
LogError("_calcDP failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!_cut(segContext, segWordInfos))
|
||||
{
|
||||
LogError("_cut failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MPSegment::cut(const string& str, vector<TrieNodeInfo>& segWordInfos)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
if(str.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Unicode sentence;
|
||||
|
||||
if(!TransCode::decode(str, sentence))
|
||||
{
|
||||
LogError("TransCode::decode failed.");
|
||||
return false;
|
||||
}
|
||||
return cut(sentence.begin(), sentence.end(), segWordInfos);
|
||||
|
||||
}
|
||||
|
||||
bool MPSegment::_calcDAG(SegmentContext& segContext)const
|
||||
{
|
||||
if(segContext.empty())
|
||||
{
|
||||
LogError("segContext empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Unicode unicode;
|
||||
for(uint i = 0; i < segContext.size(); i++)
|
||||
{
|
||||
unicode.clear();
|
||||
for(uint j = i ; j < segContext.size(); j++)
|
||||
{
|
||||
unicode.push_back(segContext[j].uniCh);
|
||||
}
|
||||
|
||||
vector<pair<uint, const TrieNodeInfo*> > vp;
|
||||
if(_trie.find(unicode, vp))
|
||||
{
|
||||
for(uint j = 0; j < vp.size(); j++)
|
||||
{
|
||||
uint nextp = vp[j].first + i;
|
||||
segContext[i].dag[nextp] = vp[j].second;
|
||||
//cout<<vp[j].first<<endl;
|
||||
//LogDebug(vp[j].second->toString());
|
||||
}
|
||||
}
|
||||
if(segContext[i].dag.end() == segContext[i].dag.find(i))
|
||||
{
|
||||
segContext[i].dag[i] = NULL;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MPSegment::_calcDP(SegmentContext& segContext)const
|
||||
{
|
||||
if(segContext.empty())
|
||||
{
|
||||
LogError("segContext empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = segContext.size() - 1; i >= 0; i--)
|
||||
{
|
||||
segContext[i].pInfo = NULL;
|
||||
segContext[i].weight = MIN_DOUBLE;
|
||||
for(DagType::const_iterator it = segContext[i].dag.begin(); it != segContext[i].dag.end(); it++)
|
||||
{
|
||||
uint nextPos = it->first;
|
||||
const TrieNodeInfo* p = it->second;
|
||||
double val = 0.0;
|
||||
if(nextPos + 1 < segContext.size())
|
||||
{
|
||||
val += segContext[nextPos + 1].weight;
|
||||
}
|
||||
|
||||
if(p)
|
||||
{
|
||||
val += p->logFreq;
|
||||
}
|
||||
else
|
||||
{
|
||||
val += _trie.getMinLogFreq();
|
||||
}
|
||||
if(val > segContext[i].weight)
|
||||
{
|
||||
segContext[i].pInfo = p;
|
||||
segContext[i].weight = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool MPSegment::_cut(SegmentContext& segContext, vector<TrieNodeInfo>& res)const
|
||||
{
|
||||
uint i = 0;
|
||||
while(i < segContext.size())
|
||||
{
|
||||
const TrieNodeInfo* p = segContext[i].pInfo;
|
||||
if(p)
|
||||
{
|
||||
res.push_back(*p);
|
||||
i += p->word.size();
|
||||
}
|
||||
else//single chinese word
|
||||
{
|
||||
TrieNodeInfo nodeInfo;
|
||||
nodeInfo.word.push_back(segContext[i].uniCh);
|
||||
nodeInfo.freq = 0;
|
||||
nodeInfo.logFreq = _trie.getMinLogFreq();
|
||||
res.push_back(nodeInfo);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef SEGMENT_UT
|
||||
using namespace CppJieba;
|
||||
|
||||
int main()
|
||||
{
|
||||
MPSegment segment;
|
||||
segment.init();
|
||||
if(!segment._loadSegDict("../dicts/segdict.gbk.v3.0"))
|
||||
{
|
||||
cerr<<"1"<<endl;
|
||||
return 1;
|
||||
}
|
||||
//segment.init("dicts/jieba.dict.utf8");
|
||||
//ifstream ifile("testtitle.gbk");
|
||||
ifstream ifile("badcase");
|
||||
vector<string> res;
|
||||
string line;
|
||||
while(getline(ifile, line))
|
||||
{
|
||||
res.clear();
|
||||
segment.cut(line, res);
|
||||
PRINT_VECTOR(res);
|
||||
getchar();
|
||||
}
|
||||
|
||||
segment.dispose();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
/************************************
|
||||
* file enc : ASCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#ifndef CPPJIEBA_MPSEGMENT_H
|
||||
#define CPPJIEBA_MPSEGMENT_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include "Limonp/logger.hpp"
|
||||
#include "Trie.h"
|
||||
#include "globals.h"
|
||||
#include "ISegment.hpp"
|
||||
#include "SegmentBase.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
typedef vector<SegmentChar> SegmentContext;
|
||||
|
||||
class MPSegment: public SegmentBase
|
||||
{
|
||||
private:
|
||||
Trie _trie;
|
||||
|
||||
public:
|
||||
MPSegment(){};
|
||||
virtual ~MPSegment(){dispose();};
|
||||
public:
|
||||
bool init(const char* const filePath);
|
||||
bool dispose();
|
||||
public:
|
||||
//bool cut(const string& str, vector<TrieNodeInfo>& segWordInfos)const;
|
||||
bool cut(const string& str, vector<string>& res)const;
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const;
|
||||
bool cut(const string& str, vector<TrieNodeInfo>& segWordInfos)const;
|
||||
bool cut(Unicode::const_iterator begin , Unicode::const_iterator end, vector<TrieNodeInfo>& segWordInfos)const;
|
||||
//virtual bool cut(const string& str, vector<string>& res)const;
|
||||
|
||||
private:
|
||||
bool _calcDAG(SegmentContext& segContext)const;
|
||||
bool _calcDP(SegmentContext& segContext)const;
|
||||
bool _cut(SegmentContext& segContext, vector<TrieNodeInfo>& res)const;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
264
src/MPSegment.hpp
Normal file
264
src/MPSegment.hpp
Normal file
@ -0,0 +1,264 @@
|
||||
/************************************
|
||||
* file enc : ASCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#ifndef CPPJIEBA_MPSEGMENT_H
|
||||
#define CPPJIEBA_MPSEGMENT_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include "Limonp/logger.hpp"
|
||||
#include "Trie.hpp"
|
||||
#include "ISegment.hpp"
|
||||
#include "SegmentBase.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
struct SegmentChar
|
||||
{
|
||||
uint16_t uniCh;
|
||||
DagType dag;
|
||||
const TrieNodeInfo * pInfo;
|
||||
double weight;
|
||||
|
||||
SegmentChar(uint16_t uni):uniCh(uni), pInfo(NULL), weight(0.0)
|
||||
{
|
||||
}
|
||||
};
|
||||
typedef vector<SegmentChar> SegmentContext;
|
||||
|
||||
class MPSegment: public SegmentBase
|
||||
{
|
||||
private:
|
||||
Trie _trie;
|
||||
|
||||
public:
|
||||
MPSegment(){};
|
||||
virtual ~MPSegment(){dispose();};
|
||||
public:
|
||||
bool init(const char* const filePath)
|
||||
{
|
||||
if(_getInitFlag())
|
||||
{
|
||||
LogError("already inited before now.");
|
||||
return false;
|
||||
}
|
||||
if(!_trie.init())
|
||||
{
|
||||
LogError("_trie.init failed.");
|
||||
return false;
|
||||
}
|
||||
LogInfo("_trie.loadDict(%s) start...", filePath);
|
||||
if(!_trie.loadDict(filePath))
|
||||
{
|
||||
LogError("_trie.loadDict faield.");
|
||||
return false;
|
||||
}
|
||||
LogInfo("_trie.loadDict end.");
|
||||
return _setInitFlag(true);
|
||||
}
|
||||
bool dispose()
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_trie.dispose();
|
||||
_setInitFlag(false);
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
//bool cut(const string& str, vector<TrieNodeInfo>& segWordInfos)const;
|
||||
bool cut(const string& str, vector<string>& res)const
|
||||
{
|
||||
return SegmentBase::cut(str, res);
|
||||
}
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
vector<TrieNodeInfo> segWordInfos;
|
||||
if(!cut(begin, end, segWordInfos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string tmp;
|
||||
for(uint i = 0; i < segWordInfos.size(); i++)
|
||||
{
|
||||
if(TransCode::encode(segWordInfos[i].word, tmp))
|
||||
{
|
||||
res.push_back(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError("encode failed.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool cut(const string& str, vector<TrieNodeInfo>& segWordInfos)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
if(str.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Unicode sentence;
|
||||
|
||||
if(!TransCode::decode(str, sentence))
|
||||
{
|
||||
LogError("TransCode::decode failed.");
|
||||
return false;
|
||||
}
|
||||
return cut(sentence.begin(), sentence.end(), segWordInfos);
|
||||
|
||||
}
|
||||
bool cut(Unicode::const_iterator begin , Unicode::const_iterator end, vector<TrieNodeInfo>& segWordInfos)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
SegmentContext segContext;
|
||||
for(Unicode::const_iterator it = begin; it != end; it++)
|
||||
{
|
||||
segContext.push_back(SegmentChar(*it));
|
||||
}
|
||||
|
||||
//calc DAG
|
||||
if(!_calcDAG(segContext))
|
||||
{
|
||||
LogError("_calcDAG failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!_calcDP(segContext))
|
||||
{
|
||||
LogError("_calcDP failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!_cut(segContext, segWordInfos))
|
||||
{
|
||||
LogError("_cut failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//virtual bool cut(const string& str, vector<string>& res)const;
|
||||
|
||||
private:
|
||||
bool _calcDAG(SegmentContext& segContext)const
|
||||
{
|
||||
if(segContext.empty())
|
||||
{
|
||||
LogError("segContext empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Unicode unicode;
|
||||
for(uint i = 0; i < segContext.size(); i++)
|
||||
{
|
||||
unicode.clear();
|
||||
for(uint j = i ; j < segContext.size(); j++)
|
||||
{
|
||||
unicode.push_back(segContext[j].uniCh);
|
||||
}
|
||||
|
||||
vector<pair<uint, const TrieNodeInfo*> > vp;
|
||||
if(_trie.find(unicode, vp))
|
||||
{
|
||||
for(uint j = 0; j < vp.size(); j++)
|
||||
{
|
||||
uint nextp = vp[j].first + i;
|
||||
segContext[i].dag[nextp] = vp[j].second;
|
||||
//cout<<vp[j].first<<endl;
|
||||
//LogDebug(vp[j].second->toString());
|
||||
}
|
||||
}
|
||||
if(segContext[i].dag.end() == segContext[i].dag.find(i))
|
||||
{
|
||||
segContext[i].dag[i] = NULL;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool _calcDP(SegmentContext& segContext)const
|
||||
{
|
||||
if(segContext.empty())
|
||||
{
|
||||
LogError("segContext empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = segContext.size() - 1; i >= 0; i--)
|
||||
{
|
||||
segContext[i].pInfo = NULL;
|
||||
segContext[i].weight = MIN_DOUBLE;
|
||||
for(DagType::const_iterator it = segContext[i].dag.begin(); it != segContext[i].dag.end(); it++)
|
||||
{
|
||||
uint nextPos = it->first;
|
||||
const TrieNodeInfo* p = it->second;
|
||||
double val = 0.0;
|
||||
if(nextPos + 1 < segContext.size())
|
||||
{
|
||||
val += segContext[nextPos + 1].weight;
|
||||
}
|
||||
|
||||
if(p)
|
||||
{
|
||||
val += p->logFreq;
|
||||
}
|
||||
else
|
||||
{
|
||||
val += _trie.getMinLogFreq();
|
||||
}
|
||||
if(val > segContext[i].weight)
|
||||
{
|
||||
segContext[i].pInfo = p;
|
||||
segContext[i].weight = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
bool _cut(SegmentContext& segContext, vector<TrieNodeInfo>& res)const
|
||||
{
|
||||
uint i = 0;
|
||||
while(i < segContext.size())
|
||||
{
|
||||
const TrieNodeInfo* p = segContext[i].pInfo;
|
||||
if(p)
|
||||
{
|
||||
res.push_back(*p);
|
||||
i += p->word.size();
|
||||
}
|
||||
else//single chinese word
|
||||
{
|
||||
TrieNodeInfo nodeInfo;
|
||||
nodeInfo.word.push_back(segContext[i].uniCh);
|
||||
nodeInfo.freq = 0;
|
||||
nodeInfo.logFreq = _trie.getMinLogFreq();
|
||||
res.push_back(nodeInfo);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,125 +0,0 @@
|
||||
#include "MixSegment.h"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
MixSegment::MixSegment()
|
||||
{
|
||||
}
|
||||
|
||||
MixSegment::~MixSegment()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
bool MixSegment::init(const char* const mpSegDict, const char* const hmmSegDict)
|
||||
{
|
||||
if(_getInitFlag())
|
||||
{
|
||||
LogError("inited.");
|
||||
return false;
|
||||
}
|
||||
if(!_mpSeg.init(mpSegDict))
|
||||
{
|
||||
LogError("_mpSeg init");
|
||||
return false;
|
||||
}
|
||||
if(!_hmmSeg.init(hmmSegDict))
|
||||
{
|
||||
LogError("_hmmSeg init");
|
||||
return false;
|
||||
}
|
||||
return _setInitFlag(true);
|
||||
}
|
||||
|
||||
bool MixSegment::dispose()
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_mpSeg.dispose();
|
||||
_hmmSeg.dispose();
|
||||
_setInitFlag(false);
|
||||
return true;
|
||||
}
|
||||
bool MixSegment::cut(const string& str, vector<string>& res)const
|
||||
{
|
||||
return SegmentBase::cut(str, res);
|
||||
}
|
||||
|
||||
bool MixSegment::cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
if(begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vector<TrieNodeInfo> infos;
|
||||
if(!_mpSeg.cut(begin, end, infos))
|
||||
{
|
||||
LogError("mpSeg cutDAG failed.");
|
||||
return false;
|
||||
}
|
||||
Unicode unico;
|
||||
vector<Unicode> hmmRes;
|
||||
string tmp;
|
||||
for(uint i= 0; i < infos.size(); i++)
|
||||
{
|
||||
TransCode::encode(infos[i].word,tmp);
|
||||
if(1 == infos[i].word.size())
|
||||
{
|
||||
unico.push_back(infos[i].word[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!unico.empty())
|
||||
{
|
||||
hmmRes.clear();
|
||||
if(!_hmmSeg.cut(unico.begin(), unico.end(), hmmRes))
|
||||
{
|
||||
LogError("_hmmSeg cut failed.");
|
||||
return false;
|
||||
}
|
||||
for(uint j = 0; j < hmmRes.size(); j++)
|
||||
{
|
||||
TransCode::encode(hmmRes[j], tmp);
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
unico.clear();
|
||||
TransCode::encode(infos[i].word, tmp);
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
if(!unico.empty())
|
||||
{
|
||||
hmmRes.clear();
|
||||
if(!_hmmSeg.cut(unico.begin(), unico.end(), hmmRes))
|
||||
{
|
||||
LogError("_hmmSeg cut failed.");
|
||||
return false;
|
||||
}
|
||||
for(uint j = 0; j < hmmRes.size(); j++)
|
||||
{
|
||||
TransCode::encode(hmmRes[j], tmp);
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MIXSEGMENT_UT
|
||||
using namespace CppJieba;
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,28 +0,0 @@
|
||||
#ifndef CPPJIEBA_MIXSEGMENT_H
|
||||
#define CPPJIEBA_MIXSEGMENT_H
|
||||
|
||||
#include "MPSegment.h"
|
||||
#include "HMMSegment.h"
|
||||
#include "Limonp/str_functs.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
class MixSegment: public SegmentBase
|
||||
{
|
||||
private:
|
||||
MPSegment _mpSeg;
|
||||
HMMSegment _hmmSeg;
|
||||
public:
|
||||
MixSegment();
|
||||
virtual ~MixSegment();
|
||||
public:
|
||||
bool init(const char* const _mpSegDict, const char* const _hmmSegDict);
|
||||
bool dispose();
|
||||
public:
|
||||
//virtual bool cut(const string& str, vector<string>& res) const;
|
||||
bool cut(const string& str, vector<string>& res)const;
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
128
src/MixSegment.hpp
Normal file
128
src/MixSegment.hpp
Normal file
@ -0,0 +1,128 @@
|
||||
#ifndef CPPJIEBA_MIXSEGMENT_H
|
||||
#define CPPJIEBA_MIXSEGMENT_H
|
||||
|
||||
#include "MPSegment.hpp"
|
||||
#include "HMMSegment.hpp"
|
||||
#include "Limonp/str_functs.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
class MixSegment: public SegmentBase
|
||||
{
|
||||
private:
|
||||
MPSegment _mpSeg;
|
||||
HMMSegment _hmmSeg;
|
||||
public:
|
||||
MixSegment()
|
||||
{
|
||||
}
|
||||
virtual ~MixSegment()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
public:
|
||||
bool init(const char* const mpSegDict, const char* const hmmSegDict)
|
||||
{
|
||||
if(_getInitFlag())
|
||||
{
|
||||
LogError("inited.");
|
||||
return false;
|
||||
}
|
||||
if(!_mpSeg.init(mpSegDict))
|
||||
{
|
||||
LogError("_mpSeg init");
|
||||
return false;
|
||||
}
|
||||
if(!_hmmSeg.init(hmmSegDict))
|
||||
{
|
||||
LogError("_hmmSeg init");
|
||||
return false;
|
||||
}
|
||||
return _setInitFlag(true);
|
||||
}
|
||||
bool dispose()
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_mpSeg.dispose();
|
||||
_hmmSeg.dispose();
|
||||
_setInitFlag(false);
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
//virtual bool cut(const string& str, vector<string>& res) const;
|
||||
bool cut(const string& str, vector<string>& res)const
|
||||
{
|
||||
return SegmentBase::cut(str, res);
|
||||
}
|
||||
bool cut(Unicode::const_iterator begin, Unicode::const_iterator end, vector<string>& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not inited.");
|
||||
return false;
|
||||
}
|
||||
if(begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vector<TrieNodeInfo> infos;
|
||||
if(!_mpSeg.cut(begin, end, infos))
|
||||
{
|
||||
LogError("mpSeg cutDAG failed.");
|
||||
return false;
|
||||
}
|
||||
Unicode unico;
|
||||
vector<Unicode> hmmRes;
|
||||
string tmp;
|
||||
for(uint i= 0; i < infos.size(); i++)
|
||||
{
|
||||
TransCode::encode(infos[i].word,tmp);
|
||||
if(1 == infos[i].word.size())
|
||||
{
|
||||
unico.push_back(infos[i].word[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!unico.empty())
|
||||
{
|
||||
hmmRes.clear();
|
||||
if(!_hmmSeg.cut(unico.begin(), unico.end(), hmmRes))
|
||||
{
|
||||
LogError("_hmmSeg cut failed.");
|
||||
return false;
|
||||
}
|
||||
for(uint j = 0; j < hmmRes.size(); j++)
|
||||
{
|
||||
TransCode::encode(hmmRes[j], tmp);
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
unico.clear();
|
||||
TransCode::encode(infos[i].word, tmp);
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
if(!unico.empty())
|
||||
{
|
||||
hmmRes.clear();
|
||||
if(!_hmmSeg.cut(unico.begin(), unico.end(), hmmRes))
|
||||
{
|
||||
LogError("_hmmSeg cut failed.");
|
||||
return false;
|
||||
}
|
||||
for(uint j = 0; j < hmmRes.size(); j++)
|
||||
{
|
||||
TransCode::encode(hmmRes[j], tmp);
|
||||
res.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +1,6 @@
|
||||
#ifndef CPPJIEBA_SEGMENTBASE_H
|
||||
#define CPPJIEBA_SEGMENTBASE_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "ISegment.hpp"
|
||||
#include "ChineseFilter.hpp"
|
||||
#include "Limonp/str_functs.hpp"
|
||||
|
@ -6,13 +6,13 @@
|
||||
#define CPPJIEBA_TRANSCODE_H
|
||||
|
||||
|
||||
#include "globals.h"
|
||||
#include "Limonp/str_functs.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
using namespace Limonp;
|
||||
typedef std::vector<uint16_t> Unicode;
|
||||
namespace TransCode
|
||||
{
|
||||
inline bool decode(const string& str, vector<uint16_t>& vec)
|
||||
|
390
src/Trie.cpp
390
src/Trie.cpp
@ -1,390 +0,0 @@
|
||||
/************************************
|
||||
* file enc : ASCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#include "Trie.h"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
Trie::Trie()
|
||||
{
|
||||
|
||||
_root = NULL;
|
||||
_freqSum = 0;
|
||||
_minLogFreq = MAX_DOUBLE;
|
||||
_initFlag = false;
|
||||
}
|
||||
|
||||
Trie::~Trie()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
bool Trie::init()
|
||||
{
|
||||
if(_getInitFlag())
|
||||
{
|
||||
LogError("already initted!");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_root = new TrieNode;
|
||||
}
|
||||
catch(const bad_alloc& e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(NULL == _root)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_setInitFlag(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Trie::loadDict(const char * const filePath)
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not initted.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!checkFileExist(filePath))
|
||||
{
|
||||
LogError("cann't find fiel[%s].",filePath);
|
||||
return false;
|
||||
}
|
||||
bool res = false;
|
||||
res = _trieInsert(filePath);
|
||||
if(!res)
|
||||
{
|
||||
LogError("_trieInsert failed.");
|
||||
return false;
|
||||
}
|
||||
res = _countWeight();
|
||||
if(!res)
|
||||
{
|
||||
LogError("_countWeight failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Trie::_trieInsert(const char * const filePath)
|
||||
{
|
||||
|
||||
ifstream ifile(filePath);
|
||||
string line;
|
||||
vector<string> vecBuf;
|
||||
|
||||
TrieNodeInfo nodeInfo;
|
||||
while(getline(ifile, line))
|
||||
{
|
||||
vecBuf.clear();
|
||||
splitStr(line, vecBuf, " ");
|
||||
if(3 < vecBuf.size())
|
||||
{
|
||||
LogError("line[%s] illegal.", line.c_str());
|
||||
return false;
|
||||
}
|
||||
if(!TransCode::decode(vecBuf[0], nodeInfo.word))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
nodeInfo.freq = atoi(vecBuf[1].c_str());
|
||||
if(3 == vecBuf.size())
|
||||
{
|
||||
nodeInfo.tag = vecBuf[2];
|
||||
}
|
||||
|
||||
//insert node
|
||||
if(!insert(nodeInfo))
|
||||
{
|
||||
LogError("insert node failed!");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Trie::dispose()
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool ret = _deleteNode(_root);
|
||||
if(!ret)
|
||||
{
|
||||
LogFatal("_deleteNode failed!");
|
||||
return false;
|
||||
}
|
||||
_root = NULL;
|
||||
_nodeInfoVec.clear();
|
||||
|
||||
_setInitFlag(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const TrieNodeInfo* Trie::findPrefix(const string& str)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("trie not initted!");
|
||||
return NULL;
|
||||
}
|
||||
Unicode uintVec;
|
||||
|
||||
if(!TransCode::decode(str, uintVec))
|
||||
{
|
||||
LogError("TransCode::decode failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//find
|
||||
TrieNode* p = _root;
|
||||
uint pos = 0;
|
||||
uint16_t chUni = 0;
|
||||
const TrieNodeInfo * res = NULL;
|
||||
for(uint i = 0; i < uintVec.size(); i++)
|
||||
{
|
||||
chUni = uintVec[i];
|
||||
if(p->isLeaf)
|
||||
{
|
||||
pos = p->nodeInfoVecPos;
|
||||
if(pos >= _nodeInfoVec.size())
|
||||
{
|
||||
LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
|
||||
return NULL;
|
||||
}
|
||||
res = &(_nodeInfoVec[pos]);
|
||||
|
||||
}
|
||||
if(p->hmap.find(chUni) == p->hmap.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = p->hmap[chUni];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const TrieNodeInfo* Trie::find(const string& str)const
|
||||
{
|
||||
Unicode uintVec;
|
||||
if(!TransCode::decode(str, uintVec))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return find(uintVec);
|
||||
}
|
||||
|
||||
const TrieNodeInfo* Trie::find(const Unicode& uintVec)const
|
||||
{
|
||||
if(uintVec.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return find(uintVec.begin(), uintVec.end());
|
||||
}
|
||||
|
||||
const TrieNodeInfo* Trie::find(Unicode::const_iterator begin, Unicode::const_iterator end)const
|
||||
{
|
||||
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("trie not initted!");
|
||||
return NULL;
|
||||
}
|
||||
if(begin >= end)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
TrieNode* p = _root;
|
||||
for(Unicode::const_iterator it = begin; it != end; it++)
|
||||
{
|
||||
uint16_t chUni = *it;
|
||||
if(p->hmap.find(chUni) == p-> hmap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = p->hmap[chUni];
|
||||
}
|
||||
}
|
||||
if(p->isLeaf)
|
||||
{
|
||||
uint pos = p->nodeInfoVecPos;
|
||||
if(pos < _nodeInfoVec.size())
|
||||
{
|
||||
return &(_nodeInfoVec[pos]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Trie::find(const Unicode& unico, vector<pair<uint, const TrieNodeInfo*> >& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("trie not initted!");
|
||||
return false;
|
||||
}
|
||||
TrieNode* p = _root;
|
||||
//for(Unicode::const_iterator it = begin; it != end; it++)
|
||||
for(uint i = 0; i < unico.size(); i++)
|
||||
{
|
||||
if(p->hmap.find(unico[i]) == p-> hmap.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
p = p->hmap[unico[i]];
|
||||
if(p->isLeaf)
|
||||
{
|
||||
uint pos = p->nodeInfoVecPos;
|
||||
if(pos < _nodeInfoVec.size())
|
||||
{
|
||||
res.push_back(make_pair(i, &_nodeInfoVec[pos]));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !res.empty();
|
||||
}
|
||||
|
||||
bool Trie::_deleteNode(TrieNode* node)
|
||||
{
|
||||
for(TrieNodeMap::iterator it = node->hmap.begin(); it != node->hmap.end(); it++)
|
||||
{
|
||||
TrieNode* next = it->second;
|
||||
_deleteNode(next);
|
||||
}
|
||||
|
||||
delete node;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Trie::insert(const TrieNodeInfo& nodeInfo)
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("not initted!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const Unicode& uintVec = nodeInfo.word;
|
||||
TrieNode* p = _root;
|
||||
for(uint i = 0; i < uintVec.size(); i++)
|
||||
{
|
||||
uint16_t cu = uintVec[i];
|
||||
if(NULL == p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(p->hmap.end() == p->hmap.find(cu))
|
||||
{
|
||||
TrieNode * next = NULL;
|
||||
try
|
||||
{
|
||||
next = new TrieNode;
|
||||
}
|
||||
catch(const bad_alloc& e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
p->hmap[cu] = next;
|
||||
p = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = p->hmap[cu];
|
||||
}
|
||||
}
|
||||
if(NULL == p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(p->isLeaf)
|
||||
{
|
||||
LogError("this node already inserted");
|
||||
return false;
|
||||
}
|
||||
|
||||
p->isLeaf = true;
|
||||
_nodeInfoVec.push_back(nodeInfo);
|
||||
p->nodeInfoVecPos = _nodeInfoVec.size() - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Trie::_countWeight()
|
||||
{
|
||||
if(_nodeInfoVec.empty() || 0 != _freqSum)
|
||||
{
|
||||
LogError("_nodeInfoVec is empty or _freqSum has been counted already.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//freq total freq
|
||||
for(size_t i = 0; i < _nodeInfoVec.size(); i++)
|
||||
{
|
||||
_freqSum += _nodeInfoVec[i].freq;
|
||||
}
|
||||
|
||||
if(0 == _freqSum)
|
||||
{
|
||||
LogError("_freqSum == 0 .");
|
||||
return false;
|
||||
}
|
||||
|
||||
//normalize
|
||||
for(uint i = 0; i < _nodeInfoVec.size(); i++)
|
||||
{
|
||||
TrieNodeInfo& nodeInfo = _nodeInfoVec[i];
|
||||
if(0 == nodeInfo.freq)
|
||||
{
|
||||
LogFatal("nodeInfo.freq == 0!");
|
||||
return false;
|
||||
}
|
||||
nodeInfo.logFreq = log(double(nodeInfo.freq)/double(_freqSum));
|
||||
if(_minLogFreq > nodeInfo.logFreq)
|
||||
{
|
||||
_minLogFreq = nodeInfo.logFreq;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TRIE_UT
|
||||
using namespace CppJieba;
|
||||
int main()
|
||||
{
|
||||
Trie trie;
|
||||
trie.init();
|
||||
trie.loadDict("../dicts/segdict.gbk.v2.1");
|
||||
//trie.loadDict("tmp");
|
||||
cout<<trie.getMinLogFreq()<<endl;
|
||||
trie.dispose();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
85
src/Trie.h
85
src/Trie.h
@ -1,85 +0,0 @@
|
||||
/************************************
|
||||
* file enc : ASCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#ifndef CPPJIEBA_TRIE_H
|
||||
#define CPPJIEBA_TRIE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "Limonp/str_functs.hpp"
|
||||
#include "Limonp/logger.hpp"
|
||||
#include "TransCode.hpp"
|
||||
#include "globals.h"
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
using namespace Limonp;
|
||||
struct TrieNode
|
||||
{
|
||||
TrieNodeMap hmap;
|
||||
bool isLeaf;
|
||||
uint nodeInfoVecPos;
|
||||
TrieNode()
|
||||
{
|
||||
isLeaf = false;
|
||||
nodeInfoVecPos = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Trie
|
||||
{
|
||||
|
||||
private:
|
||||
TrieNode* _root;
|
||||
vector<TrieNodeInfo> _nodeInfoVec;
|
||||
|
||||
bool _initFlag;
|
||||
int64_t _freqSum;
|
||||
double _minLogFreq;
|
||||
|
||||
public:
|
||||
Trie();
|
||||
~Trie();
|
||||
bool init();
|
||||
bool loadDict(const char * const filePath);
|
||||
bool dispose();
|
||||
|
||||
private:
|
||||
void _setInitFlag(bool on){_initFlag = on;};
|
||||
bool _getInitFlag()const{return _initFlag;};
|
||||
|
||||
public:
|
||||
const TrieNodeInfo* find(const string& str)const;
|
||||
const TrieNodeInfo* find(const Unicode& uintVec)const;
|
||||
const TrieNodeInfo* find(Unicode::const_iterator begin, Unicode::const_iterator end)const;
|
||||
bool find(const Unicode& unico, vector<pair<uint, const TrieNodeInfo*> >& res)const;
|
||||
|
||||
const TrieNodeInfo* findPrefix(const string& str)const;
|
||||
|
||||
public:
|
||||
//double getWeight(const string& str);
|
||||
//double getWeight(const Unicode& uintVec);
|
||||
//double getWeight(Unicode::const_iterator begin, Unicode::const_iterator end);
|
||||
double getMinLogFreq()const{return _minLogFreq;};
|
||||
|
||||
//int64_t getTotalCount(){return _freqSum;};
|
||||
|
||||
bool insert(const TrieNodeInfo& nodeInfo);
|
||||
|
||||
private:
|
||||
bool _trieInsert(const char * const filePath);
|
||||
bool _countWeight();
|
||||
bool _deleteNode(TrieNode* node);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
441
src/Trie.hpp
Normal file
441
src/Trie.hpp
Normal file
@ -0,0 +1,441 @@
|
||||
/************************************
|
||||
* file enc : ASCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#ifndef CPPJIEBA_TRIE_H
|
||||
#define CPPJIEBA_TRIE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "Limonp/str_functs.hpp"
|
||||
#include "Limonp/logger.hpp"
|
||||
#include "TransCode.hpp"
|
||||
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
using namespace Limonp;
|
||||
const double MIN_DOUBLE = -3.14e+100;
|
||||
const double MAX_DOUBLE = 3.14e+100;
|
||||
typedef unordered_map<uint16_t, struct TrieNode*> TrieNodeMap;
|
||||
struct TrieNode
|
||||
{
|
||||
TrieNodeMap hmap;
|
||||
bool isLeaf;
|
||||
uint nodeInfoVecPos;
|
||||
TrieNode()
|
||||
{
|
||||
isLeaf = false;
|
||||
nodeInfoVecPos = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct TrieNodeInfo
|
||||
{
|
||||
Unicode word;
|
||||
size_t freq;
|
||||
string tag;
|
||||
double logFreq; //logFreq = log(freq/sum(freq));
|
||||
TrieNodeInfo():freq(0),logFreq(0.0)
|
||||
{
|
||||
}
|
||||
TrieNodeInfo(const TrieNodeInfo& nodeInfo):word(nodeInfo.word), freq(nodeInfo.freq), tag(nodeInfo.tag), logFreq(nodeInfo.logFreq)
|
||||
{
|
||||
}
|
||||
TrieNodeInfo(const Unicode& _word):word(_word),freq(0),logFreq(MIN_DOUBLE)
|
||||
{
|
||||
}
|
||||
string toString()const
|
||||
{
|
||||
string tmp;
|
||||
TransCode::encode(word, tmp);
|
||||
return string_format("{word:%s,freq:%d, logFreq:%lf}", tmp.c_str(), freq, logFreq);
|
||||
}
|
||||
};
|
||||
typedef unordered_map<uint, const TrieNodeInfo*> DagType;
|
||||
|
||||
class Trie
|
||||
{
|
||||
|
||||
private:
|
||||
TrieNode* _root;
|
||||
vector<TrieNodeInfo> _nodeInfoVec;
|
||||
|
||||
bool _initFlag;
|
||||
int64_t _freqSum;
|
||||
double _minLogFreq;
|
||||
|
||||
public:
|
||||
Trie()
|
||||
{
|
||||
_root = NULL;
|
||||
_freqSum = 0;
|
||||
_minLogFreq = MAX_DOUBLE;
|
||||
_initFlag = false;
|
||||
}
|
||||
~Trie()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
bool init()
|
||||
{
|
||||
if(_getInitFlag())
|
||||
{
|
||||
LogError("already initted!");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_root = new TrieNode;
|
||||
}
|
||||
catch(const bad_alloc& e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(NULL == _root)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_setInitFlag(true);
|
||||
return true;
|
||||
}
|
||||
bool dispose()
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool ret = _deleteNode(_root);
|
||||
if(!ret)
|
||||
{
|
||||
LogFatal("_deleteNode failed!");
|
||||
return false;
|
||||
}
|
||||
_root = NULL;
|
||||
_nodeInfoVec.clear();
|
||||
|
||||
_setInitFlag(false);
|
||||
return ret;
|
||||
}
|
||||
bool loadDict(const char * const filePath)
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogError("not initted.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!checkFileExist(filePath))
|
||||
{
|
||||
LogError("cann't find fiel[%s].",filePath);
|
||||
return false;
|
||||
}
|
||||
bool res = false;
|
||||
res = _trieInsert(filePath);
|
||||
if(!res)
|
||||
{
|
||||
LogError("_trieInsert failed.");
|
||||
return false;
|
||||
}
|
||||
res = _countWeight();
|
||||
if(!res)
|
||||
{
|
||||
LogError("_countWeight failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void _setInitFlag(bool on){_initFlag = on;};
|
||||
bool _getInitFlag()const{return _initFlag;};
|
||||
|
||||
public:
|
||||
const TrieNodeInfo* find(const string& str)const
|
||||
{
|
||||
Unicode uintVec;
|
||||
if(!TransCode::decode(str, uintVec))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return find(uintVec);
|
||||
}
|
||||
const TrieNodeInfo* find(const Unicode& uintVec)const
|
||||
{
|
||||
if(uintVec.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return find(uintVec.begin(), uintVec.end());
|
||||
}
|
||||
const TrieNodeInfo* find(Unicode::const_iterator begin, Unicode::const_iterator end)const
|
||||
{
|
||||
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("trie not initted!");
|
||||
return NULL;
|
||||
}
|
||||
if(begin >= end)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
TrieNode* p = _root;
|
||||
for(Unicode::const_iterator it = begin; it != end; it++)
|
||||
{
|
||||
uint16_t chUni = *it;
|
||||
if(p->hmap.find(chUni) == p-> hmap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = p->hmap[chUni];
|
||||
}
|
||||
}
|
||||
if(p->isLeaf)
|
||||
{
|
||||
uint pos = p->nodeInfoVecPos;
|
||||
if(pos < _nodeInfoVec.size())
|
||||
{
|
||||
return &(_nodeInfoVec[pos]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
bool find(const Unicode& unico, vector<pair<uint, const TrieNodeInfo*> >& res)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("trie not initted!");
|
||||
return false;
|
||||
}
|
||||
TrieNode* p = _root;
|
||||
for(uint i = 0; i < unico.size(); i++)
|
||||
{
|
||||
if(p->hmap.find(unico[i]) == p-> hmap.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
p = p->hmap[unico[i]];
|
||||
if(p->isLeaf)
|
||||
{
|
||||
uint pos = p->nodeInfoVecPos;
|
||||
if(pos < _nodeInfoVec.size())
|
||||
{
|
||||
res.push_back(make_pair(i, &_nodeInfoVec[pos]));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !res.empty();
|
||||
}
|
||||
|
||||
const TrieNodeInfo* findPrefix(const string& str)const
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("trie not initted!");
|
||||
return NULL;
|
||||
}
|
||||
Unicode uintVec;
|
||||
|
||||
if(!TransCode::decode(str, uintVec))
|
||||
{
|
||||
LogError("TransCode::decode failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//find
|
||||
TrieNode* p = _root;
|
||||
uint pos = 0;
|
||||
uint16_t chUni = 0;
|
||||
const TrieNodeInfo * res = NULL;
|
||||
for(uint i = 0; i < uintVec.size(); i++)
|
||||
{
|
||||
chUni = uintVec[i];
|
||||
if(p->isLeaf)
|
||||
{
|
||||
pos = p->nodeInfoVecPos;
|
||||
if(pos >= _nodeInfoVec.size())
|
||||
{
|
||||
LogFatal("node's nodeInfoVecPos is out of _nodeInfoVec's range");
|
||||
return NULL;
|
||||
}
|
||||
res = &(_nodeInfoVec[pos]);
|
||||
|
||||
}
|
||||
if(p->hmap.find(chUni) == p->hmap.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = p->hmap[chUni];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
double getMinLogFreq()const{return _minLogFreq;};
|
||||
|
||||
bool insert(const TrieNodeInfo& nodeInfo)
|
||||
{
|
||||
if(!_getInitFlag())
|
||||
{
|
||||
LogFatal("not initted!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const Unicode& uintVec = nodeInfo.word;
|
||||
TrieNode* p = _root;
|
||||
for(uint i = 0; i < uintVec.size(); i++)
|
||||
{
|
||||
uint16_t cu = uintVec[i];
|
||||
if(NULL == p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(p->hmap.end() == p->hmap.find(cu))
|
||||
{
|
||||
TrieNode * next = NULL;
|
||||
try
|
||||
{
|
||||
next = new TrieNode;
|
||||
}
|
||||
catch(const bad_alloc& e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
p->hmap[cu] = next;
|
||||
p = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = p->hmap[cu];
|
||||
}
|
||||
}
|
||||
if(NULL == p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(p->isLeaf)
|
||||
{
|
||||
LogError("this node already inserted");
|
||||
return false;
|
||||
}
|
||||
|
||||
p->isLeaf = true;
|
||||
_nodeInfoVec.push_back(nodeInfo);
|
||||
p->nodeInfoVecPos = _nodeInfoVec.size() - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _trieInsert(const char * const filePath)
|
||||
{
|
||||
ifstream ifile(filePath);
|
||||
string line;
|
||||
vector<string> vecBuf;
|
||||
|
||||
TrieNodeInfo nodeInfo;
|
||||
while(getline(ifile, line))
|
||||
{
|
||||
vecBuf.clear();
|
||||
splitStr(line, vecBuf, " ");
|
||||
if(3 < vecBuf.size())
|
||||
{
|
||||
LogError("line[%s] illegal.", line.c_str());
|
||||
return false;
|
||||
}
|
||||
if(!TransCode::decode(vecBuf[0], nodeInfo.word))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
nodeInfo.freq = atoi(vecBuf[1].c_str());
|
||||
if(3 == vecBuf.size())
|
||||
{
|
||||
nodeInfo.tag = vecBuf[2];
|
||||
}
|
||||
|
||||
//insert node
|
||||
if(!insert(nodeInfo))
|
||||
{
|
||||
LogError("insert node failed!");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool _countWeight()
|
||||
{
|
||||
if(_nodeInfoVec.empty() || 0 != _freqSum)
|
||||
{
|
||||
LogError("_nodeInfoVec is empty or _freqSum has been counted already.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//freq total freq
|
||||
for(size_t i = 0; i < _nodeInfoVec.size(); i++)
|
||||
{
|
||||
_freqSum += _nodeInfoVec[i].freq;
|
||||
}
|
||||
|
||||
if(0 == _freqSum)
|
||||
{
|
||||
LogError("_freqSum == 0 .");
|
||||
return false;
|
||||
}
|
||||
|
||||
//normalize
|
||||
for(uint i = 0; i < _nodeInfoVec.size(); i++)
|
||||
{
|
||||
TrieNodeInfo& nodeInfo = _nodeInfoVec[i];
|
||||
if(0 == nodeInfo.freq)
|
||||
{
|
||||
LogFatal("nodeInfo.freq == 0!");
|
||||
return false;
|
||||
}
|
||||
nodeInfo.logFreq = log(double(nodeInfo.freq)/double(_freqSum));
|
||||
if(_minLogFreq > nodeInfo.logFreq)
|
||||
{
|
||||
_minLogFreq = nodeInfo.logFreq;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _deleteNode(TrieNode* node)
|
||||
{
|
||||
for(TrieNodeMap::iterator it = node->hmap.begin(); it != node->hmap.end(); it++)
|
||||
{
|
||||
TrieNode* next = it->second;
|
||||
_deleteNode(next);
|
||||
}
|
||||
|
||||
delete node;
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,36 +0,0 @@
|
||||
/************************************
|
||||
* file enc : ASCII
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
#ifndef CPPJIEBA_GLOBALS_H
|
||||
#define CPPJIEBA_GLOBALS_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
//#include <hash_map>
|
||||
#include <tr1/unordered_map>
|
||||
//#include <ext/hash_map>
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::unordered_map;
|
||||
//using __gnu_cxx::hash_map;
|
||||
//using namespace stdext;
|
||||
//typedefs
|
||||
typedef std::vector<std::string>::iterator VSI;
|
||||
typedef std::vector<uint16_t> Unicode;
|
||||
typedef Unicode::const_iterator UniConIter;
|
||||
typedef unordered_map<uint16_t, struct TrieNode*> TrieNodeMap;
|
||||
typedef unordered_map<uint16_t, double> EmitProbMap;
|
||||
|
||||
const double MIN_DOUBLE = -3.14e+100;
|
||||
const double MAX_DOUBLE = 3.14e+100;
|
||||
enum CHAR_TYPE { CHWORD = 0, DIGIT_OR_LETTER = 1, OTHERS = 2};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,9 +1,9 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "Limonp/ArgvContext.hpp"
|
||||
#include "MPSegment.h"
|
||||
#include "HMMSegment.h"
|
||||
#include "MixSegment.h"
|
||||
#include "MPSegment.hpp"
|
||||
#include "HMMSegment.hpp"
|
||||
#include "MixSegment.hpp"
|
||||
|
||||
using namespace CppJieba;
|
||||
|
||||
|
@ -7,9 +7,9 @@
|
||||
#include "Limonp/Config.hpp"
|
||||
#include "Husky/Daemon.h"
|
||||
#include "Husky/ServerFrame.h"
|
||||
#include "MPSegment.h"
|
||||
#include "HMMSegment.h"
|
||||
#include "MixSegment.h"
|
||||
#include "MPSegment.hpp"
|
||||
#include "HMMSegment.hpp"
|
||||
#include "MixSegment.hpp"
|
||||
|
||||
using namespace Husky;
|
||||
using namespace CppJieba;
|
||||
|
111
src/structs.h
111
src/structs.h
@ -1,111 +0,0 @@
|
||||
#ifndef CPPJIEBA_STRUCTS_H
|
||||
#define CPPJIEBA_STRUCTS_H
|
||||
|
||||
#include <limits>
|
||||
#include "globals.h"
|
||||
#include "Trie.h"
|
||||
#include "TransCode.hpp"
|
||||
|
||||
namespace CppJieba
|
||||
{
|
||||
|
||||
struct TrieNodeInfo
|
||||
{
|
||||
//string word;
|
||||
//size_t wLen;// the word's len , not string.length(),
|
||||
Unicode word;
|
||||
size_t freq;
|
||||
string tag;
|
||||
double logFreq; //logFreq = log(freq/sum(freq));
|
||||
TrieNodeInfo():freq(0),logFreq(0.0)
|
||||
{
|
||||
}
|
||||
TrieNodeInfo(const TrieNodeInfo& nodeInfo):word(nodeInfo.word), freq(nodeInfo.freq), tag(nodeInfo.tag), logFreq(nodeInfo.logFreq)
|
||||
{
|
||||
}
|
||||
TrieNodeInfo(const Unicode& _word):word(_word),freq(0),logFreq(MIN_DOUBLE)
|
||||
{
|
||||
}
|
||||
string toString()const
|
||||
{
|
||||
string tmp;
|
||||
TransCode::encode(word, tmp);
|
||||
return string_format("{word:%s,freq:%d, logFreq:%lf}", tmp.c_str(), freq, logFreq);
|
||||
}
|
||||
};
|
||||
|
||||
typedef unordered_map<uint, const TrieNodeInfo*> DagType;
|
||||
struct SegmentChar
|
||||
{
|
||||
uint16_t uniCh;
|
||||
DagType dag;
|
||||
const TrieNodeInfo * pInfo;
|
||||
double weight;
|
||||
|
||||
SegmentChar(uint16_t uni):uniCh(uni), pInfo(NULL), weight(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
/*const TrieNodeInfo* pInfo;
|
||||
double weight;
|
||||
SegmentChar(uint16_t unich, const TrieNodeInfo* p, double w):uniCh(unich), pInfo(p), weight(w)
|
||||
{
|
||||
}*/
|
||||
};
|
||||
/*
|
||||
struct SegmentContext
|
||||
{
|
||||
vector<SegmentChar> context;
|
||||
bool getDA
|
||||
};*/
|
||||
typedef vector<SegmentChar> SegmentContext;
|
||||
|
||||
|
||||
struct KeyWordInfo: public TrieNodeInfo
|
||||
{
|
||||
double idf;
|
||||
double weight;// log(wLen+1)*logFreq;
|
||||
KeyWordInfo():idf(0.0),weight(0.0)
|
||||
{
|
||||
}
|
||||
KeyWordInfo(const Unicode& _word):TrieNodeInfo(_word),idf(0.0),weight(0.0)
|
||||
{
|
||||
}
|
||||
KeyWordInfo(const TrieNodeInfo& trieNodeInfo):TrieNodeInfo(trieNodeInfo)
|
||||
{
|
||||
}
|
||||
string toString() const
|
||||
{
|
||||
string tmp;
|
||||
TransCode::encode(word, tmp);
|
||||
return string_format("{word:%s,weight:%lf, idf:%lf}", tmp.c_str(), weight, idf);
|
||||
}
|
||||
KeyWordInfo& operator = (const TrieNodeInfo& trieNodeInfo)
|
||||
{
|
||||
word = trieNodeInfo.word;
|
||||
freq = trieNodeInfo.freq;
|
||||
tag = trieNodeInfo.tag;
|
||||
logFreq = trieNodeInfo.logFreq;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
inline ostream& operator << (ostream& os, const KeyWordInfo& info)
|
||||
{
|
||||
string tmp;
|
||||
TransCode::encode(info.word, tmp);
|
||||
return os << "{words:" << tmp << ", weight:" << info.weight << ", idf:" << info.idf << "}";
|
||||
}
|
||||
|
||||
//inline string joinWordInfos(const vector<KeyWordInfo>& vec)
|
||||
//{
|
||||
// vector<string> tmp;
|
||||
// for(uint i = 0; i < vec.size(); i++)
|
||||
// {
|
||||
// tmp.push_back(vec[i].toString());
|
||||
// }
|
||||
// return joinStr(tmp, ",");
|
||||
//}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user