在C++中呼叫Jieba進行中文分詞
阿新 • • 發佈:2019-02-15
背景
之前有個小專案用到了中文分詞,但當時使用的ICTCLAS需要每個月下載證書,很不方便。後來在網上找到了一個開源的python實現的中文分詞器Jieba,可以使用pip直接安裝本地。但之前的專案是c++實現的,所以需要考慮跨語言的呼叫問題。
Python.h中提供了PyRun_SimpleString()方法,可以執行簡單的python語句,但無法獲取輸出的資料。另外也提供了PyObject_CallObject(),可以將python命令的執行結果作為PyObject物件指標返回。
程式碼實現:類定義
class PyTextCut{
private :
PyObject *pName,*pModule,*pDict,*pFunc;
public:
PyTextCut();
string cut(string input); //Jieba分詞的呼叫入口
~PyTextCut();
private:
int init();
};
程式碼實現:初始化
PyTextCut::PyTextCut(){
init();
}
string PyTextCut::init()
{
Py_Initialize();
// 檢查初始化是否成功
if ( !Py_IsInitialized() ) {
return -1;
}
// 添加當前路徑
PyRun_SimpleString("import sys");
PyRun_SimpleString("reload(sys)");
PyRun_SimpleString("sys.setdefaultencoding('utf8')");
// 載入jieba
pName = PyString_FromString("jieba");
pModule = PyImport_Import(pName);
if ( !pModule ) {
printf("can't find jieba");
return -1;
}
pDict = PyModule_GetDict(pModule);
if ( !pDict ) {
return -1;
}
//查詢函式cut
pFunc = PyDict_GetItemString(pDict, "cut");
if ( !pFunc || !PyCallable_Check(pFunc) ) {
printf("can't find function [cut]");
return -1;
}
}
程式碼實現:呼叫分詞方法
string PyTextCut::cut(string input){
string output = "";
PyObject *pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",input.c_str()));
// 執行cut
PyObject *pRet = PyObject_CallObject(pFunc, pArgs);
//因為返回的是生成器型別的物件,所以必須用迭代器來訪問
PyObject *iter = PyObject_GetIter(pRet);
if( !iter ){
printf("can't find iter");
return input;
}
PyObject *next = NULL;
while(true){
next = PyIter_Next(iter);
if( !next ){
break;
}
string str = PyString_AsString(next);
output += str + " ";//將分詞結果用空格隔開
}
Py_DECREF(pArgs);
Py_DECREF(pRet);
Py_DECREF(iter);
return output;
}
程式碼實現:減少引用計數,釋放資源
PyTextCut::~PyTextCut(){
if(pFunc != NULL) Py_DECREF(pFunc);
if(pDict != NULL) Py_DECREF(pDict);
if(pModule != NULL) Py_DECREF(pModule);
if(pName != NULL) Py_DECREF(pName);
// 釋放
Py_Finalize();
}