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
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即可