Windows 下Java呼叫CRF++詳解
轉自:http://www.cnblogs.com/i-bugs/p/3580383.html
1.步驟一覽
2.步驟詳情
2.1.環境準備
Swig(Simplified Wrapper and Interface Generator)下載,Windows作業系統直接解壓即可使用
CRF++(Yet Another CRF toolkit)下載,CRF++-0.58zip和CRF++-0.58.tar.gz兩個版本最好都下載,方便我們後續操作
VS2013下載,本文用的是試用版
2.2.Swig包裝CRF++
2.2.1.包裝檔案準備
用Swig包裝CRF++主要用到以下原始檔,CRF++-0.58.zip\CRF++-0.58\sdk\crfpp.h, CRF++-0.58.zip\CRF++-0.58\sdk\libcrfpp.lib
還需要一個SWIG介面檔案,介面檔案CRFPP.i我們直接從CRF++-0.58.tar.gz\CRF++-0.58\swig目錄下解壓拷貝出來,順便也將version.h拷出來,與其它原檔案放在一起。目錄結構如下:
現在來看一下介面檔案裡的內容
%module CRFPP %include exception.i %{ #include "crfpp.h" %} %newobject surface; %exception { try { $action } catch (char *e) { SWIG_exception (SWIG_RuntimeError, e); } catch (const char *e) { SWIG_exception (SWIG_RuntimeError, (char*)e); } } %feature("notabstract") CRFPP::Model; %feature("notabstract") CRFPP::Tagger; %ignore CRFPP::createModel; %ignore CRFPP::createModelFromArray; %ignore CRFPP::createTagger; %ignore CRFPP::getTaggerError; %ignore CRFPP::getLastError; %extend CRFPP::Model { Model(const char *arg); } %extend CRFPP::Tagger { Tagger(const char *arg); } %{ void delete_CRFPP_Model (CRFPP::Model *t) { delete t; t = 0; } CRFPP::Model* new_CRFPP_Model(const char *arg) { CRFPP::Model *tagger = CRFPP::createModel(arg); if (!tagger) throw CRFPP::getLastError(); return tagger; } void delete_CRFPP_Tagger (CRFPP::Tagger *t) { delete t; t = 0; } CRFPP::Tagger* new_CRFPP_Tagger (const char *arg) { CRFPP::Tagger *tagger = CRFPP::createTagger(arg); if (!tagger) throw CRFPP::getLastError(); return tagger; } %} %include crfpp.h %include version.h
複製程式碼
由於CRFF.i檔案和crfpp.h位於同一目錄,故將倒數第二行更改。另外如果沒有version.h檔案,把最後一行%include version.h刪去即可
2.2.2包裝檔案
在命令列cmd下執行:C:\swigwin-2.0.12\swig.exe -c++ -java -package com.ibugs.crfpp D:\CRF++-0.58\sdk\CRFPP.i
其中C:\swigwin-2.0.12\swig.exe 為Swig的解壓目錄,D:\CRF++-0.58\sdk\CRFPP.i為CRFPP.i放置目錄。另外-package com.ibugs.crfpp,設定編譯後java檔案的包名,包名大家可以自己設定。執行後會生成以下檔案,其中CRFPP_wrap.cxx包裝檔案為編譯動態鏈使用;*.java檔案在呼叫java專案中引入。
2.3.編譯動態鏈庫
2.3.1.建立DLL工程
在VS新建DLL專案工程,
千萬要將Application type設定為DLL,這樣就將工程建好了。然後將CRFPP_wrap.cxx複製到工程中即可
2.3.2.編譯動態鏈庫
直接右鍵工程Build,好像出錯了。
錯誤資訊提示找不到jni.h檔案。jni.h檔案為jdk安裝目錄自帶庫,那我們就要配置包含目錄。右鍵工程Properties開啟如下,並在C/C++>>General>>Additional Include Directories新增包含目錄
再來Build一下吧,很不幸又出錯了
錯誤資訊提示找不到相應的函式,在sdk目錄下還有一個libcrfpp.lib包,把它拷入專案中來。然後Build,好像這次真的成功啦
在專案物理目錄中可以看到生成的動態鏈庫檔案
2.4.總算可以例項了
建立一個Java專案,目錄結構如下:其中包名和Swig包裝設定的包名一致,將Swig生成的相應Java檔案拷入專案中;同時將生成的動態鏈庫CRFPP.dll放入lib目錄中,其中libcrfpp.dll檔案在CRF++-0.58.zip\目錄下
測試檔案test.java,可以從CRF++-0.58.tar.gz\CRF++-0.58\swig目錄獲得,如下:
package com.ibugs.crfpp;
public class test {
public static void main(String[] argv) {
//Tagger tagger = new Tagger("-m W://model -v 3 -n2");
Tagger tagger = new Tagger("-m D://CRF++-0.58/CRF++-0.58/chinese/model -v 3 -n2");
// clear internal context
tagger.clear();
// add context
tagger.add("Confidence NN");
tagger.add("in IN");
tagger.add("the DT");
tagger.add("pound NN");
tagger.add("is VBZ");
tagger.add("widely RB");
tagger.add("expected VBN");
tagger.add("to TO");
tagger.add("take VB");
tagger.add("another DT");
tagger.add("sharp JJ");
tagger.add("dive NN");
tagger.add("if IN");
tagger.add("trade NN");
tagger.add("figures NNS");
tagger.add("for IN");
tagger.add("September NNP");
System.out.println("column size: " + tagger.xsize());
System.out.println("token size: " + tagger.size());
System.out.println("tag size: " + tagger.ysize());
System.out.println("tagset information:");
for (int i = 0; i < tagger.ysize(); ++i) {
System.out.println("tag " + i + " " + tagger.yname(i));
}
// parse and change internal stated as 'parsed'
if (!tagger.parse())
return;
System.out.println("conditional prob=" + tagger.prob()
+ " log(Z)=" + tagger.Z());
for (int i = 0; i < tagger.size(); ++i) {
for (int j = 0; j < tagger.xsize(); ++j) {
System.out.print(tagger.x(i, j) + "\t");
}
System.out.print(tagger.y2(i) + "\t");
System.out.print("\n");
System.out.print("Details");
for (int j = 0; j < tagger.ysize(); ++j) {
System.out.print("\t" + tagger.yname(j) + "/prob=" + tagger.prob(i,j)
+ "/alpha=" + tagger.alpha(i, j)
+ "/beta=" + tagger.beta(i, j));
}
System.out.print("\n");
}
// when -n20 is specified, you can access nbest outputs
System.out.println("nbest outputs:");
for (int n = 0; n < 10; ++n) {
if (! tagger.next()) break;
System.out.println("nbest n=" + n + "\tconditional prob=" + tagger.prob());
// you can access any information using tagger.y()...
}
System.out.println("Done");
System.out.println();
}
static {
try {
//System.loadLibrary(CRFPP); System.loadLibrary("./lib/libcrfpp); System.loadLibrary("./lib/CRFPP");
} catch (UnsatisfiedLinkError e) {
System.err.println("Cannot load the example native code.\nMake sure your LD_LIBRARY_PATH contains \'.\'\n" + e);
e.printStackTrace();
System.exit(1);
}
}
}
需要修改程式碼
指定模板檔案:Tagger tagger = new Tagger("-m W://model -v 3 -n2"); ==〉 Tagger tagger = new Tagger("-m D://CRF++-0.58/CRF++-0.58/chinese/model -v 3 -n2"); 其中model為指定的模板檔案
指定動態鏈庫檔案:System.loadLibrary("CRFPP"); ==〉System.loadLibrary("./lib/libcrfpp); System.loadLibrary("./lib/CRFPP");
總算可以結束啦,執行java程式吧!祝你好運沒有其它什麼錯誤。
另外,可以將Swig工具嵌入到VS中執行,在Tools工具條新增外部工具
其中的Arguments:-c++ -java -package com.ibugs.crfpp $(ItemFileName)$(ItemExt)
執行時,將CRFPP.i檔案拷入工程中並選中,在Tools找到Swig點選即執行
3.小結
Java呼叫C++語言其實並不難,關鍵是不熟悉整個流程。
搞了半天好像自己編譯的CRFPP.dll沒太大的作用,直接在工程中引用CRF++-0.58.zip\目錄下libcrfpp.dll即可(這句話有問題,我試了就沒有這個檔案不行!!!!