在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
参考文章: 参考文章1中,在windows中成功在Ruby中调用了ICTCLAS4J,当环境迁到Cygwin中时,出现了一些错误。本文中,将修正这些错误,在Cygwin中通过RJB在Ruby中调用ICTCLAS4J 先说明几个问题:
下面来逐步解决出现的问题: 1. 将环境迁移到cygwin下 安装好Ruby , RJB后 , 运行 require 'rubygems' require 'rjb' Rjb::load str = Rjb::import("java.lang.String")
得到错误 Error occurred during initialization of VM java/lang/NoClassDefFoundError: java/lang/Object
如果Google这个错误,可以知道是rt.jar没有载入进来,但是无论怎么设置Rjb::load 的 classpath 参数都是无效的,比如 require 'rubygems' require 'rjb' Rjb::load(classpath = ".;c:\\Java\\jdk1.6.0_18\\jre\\lib\\rt.jar") str = Rjb::import("java.lang.String") 得到的是一样的错误,说明不是classpath的问题 问题分析:(如果只需要解决方案,可以跳过问题分析,因为这个问题分析只是臆测,并未得到证实) 如果运行java –verbose,可以看到java载入类的顺序大致如下: [Loaded java.lang.Object from shared objects file] [Loaded java.io.Serializable from shared objects file] [Loaded java.lang.Comparable from shared objects file] [Loaded java.lang.CharSequence from shared objects file] [Loaded java.lang.String from shared objects file] ... [Opened C:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.nio.charset.Charset$3 from C:\Java\jdk1.6.0_18\jre\lib\rt.jar]
为了启动速度,JAVA 6开始将一些类预先载入,不再依赖于rt.jar,也就是classpath的读取在预载入之后,预载入中没有 rt.jar,就会出现错误
java -Xbootclasspath:c:\\Java\\jdk1.6.0_18\\jre\\lib\\rt.jar -verbose 结果如下: [Opened c:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.lang.Object from c:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.io.Serializable from c:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.lang.Comparable from c:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.lang.CharSequence from c:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.lang.String from c:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.lang.reflect.GenericDeclaration from c:\Java\jdk1.6.0_18\jre\lib\rt.jar] That’s Great! 问题解决: 将测试代码改成 require 'rubygems' require 'rjb' Rjb::load(classpath = "." , [ "-Xbootclasspath:c:\\Java\\jdk1.6.0_18\\jre\\lib\\rt.jar" ]) str = Rjb::import("java.lang.String") 前面的错误将解决,我们也将迎来新的错误: Error occurred during initialization of VM java.lang.UnsatisfiedLinkError: no zip in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734) at java.lang.Runtime.loadLibrary0(Runtime.java:823) at java.lang.System.loadLibrary(System.java:1028) at java.lang.System.initializeSystemClass(System.java:1086) 2. no zip in java.library.path 显然因为zip.dll没有包含在library路径中,很自然有下面的解决方案 require 'rubygems' require 'rjb' Rjb::load(classpath = "." , [ "-Xbootclasspath:c:\\Java\\jdk1.6.0_18\\jre\\lib\\rt.jar" , "-Djava.library.path=c:\\Java\\jdk1.6.0_18\\jre\\bin" ]) str = Rjb::import("java.lang.String") 不过运行后 no zip 依旧 问题分析: zip.dll 是在 rt.jar的类要求链接的库,rt.jar都是预载入的,zip.dll当然也要预载入… 问题解决: require 'rubygems' require 'rjb' Rjb::load(classpath = "." , [ "-Xbootclasspath:c:\\Java\\jdk1.6.0_18\\jre\\lib\\rt.jar" , "-Dsun.boot.library.path=c:\\Java\\jdk1.6.0_18\\jre\\bin" ]) str = Rjb::import("java.lang.String") input = str.new("we got it") puts input.toString() We got it 3. 至此,RJB基本可以在cygwin下使用,但是当我们使用ICTCLAS的时候,还是出现了一些问题的 先根据参考文章3,编译ICTCLAS4J,因为我们在之后要hack ICTCLAS4J 测试代码: require 'rubygems' require 'rjb' root_ICTCLAS = "C:\\cygwin\\home\\Tachikoma\\workspace\\try\\ICTCLAS" root_jdk = "c:\\Java\\jdk1.6.0_18" Rjb::load(classpath = ".;#{root_ICTCLAS}\\bin;#{root_ICTCLAS}\\commons-lang-#2.5\\commons-lang-2.5.jar" , [ "-Xbootclasspath:#{root_jdk}\\jre\\lib\\rt.jar" , "-Dsun.boot.library.path=#{root_jdk}\\jre\\bin" , "-Duser.dir=#{root_ICTCLAS}" ]) segtag_class = Rjb::import('org.ictclas4j.segment.SegTag') segtag = segtag_class.new_with_sig("I",1) seg_res = segtag.split("今天好累...") result = seg_res.getFinalResult() puts result 运行后出现错误: test.rb:12:in `method_missing': unknown exception (NullPointerException) from test.rb:12
问题分析: 猜测错误是没有用的,只能侵入ICTCLAS4J的代码,看个究竟。略去调试过程,得到的第一个问题是在org\ictclas4j\bean\Dictionary.java 71行,file.canRead()返回false。解释一下:ICTCLAS4j/Data中的数据文件没有读取权限,所以返回了空指针,导致失败。这个问题涉及到Windows,Cygwin,Ruby,RJB,JAVA之间的权限联动问题,我也说不清楚,只提供解决方法。发现了file = new File(filename) ,当filename为绝对路径时,具有读权限,为相对路径是,没有读权限。
file = new File(filename); filename = file.getAbsolutePath(); file = new File(filename); (就两个地方需要修改,就不重构提取函数了) 运行代码,错误依旧? 由于省去了调试过程,所以看不到出错地点,不过我确定文件权限的问题,已经就此解决 那么剩下的错误是由什么引起的? 4. GBK的错误 我们在org\ictclas4j\bean\Dictionary.java 125行左右处理IOException的代码改成如下 } catch (IOException e) { e.printStackTrace(); //logger.error(e); }
(关于ICTCLAS4源代码作者如此处理这个错误…发点牢骚,logger只让程序员看到,但是用户也应当看到一些错误信息) 再运行测试代码,得到错误: java.io.UnsupportedEncodingException: GBK at java.lang.StringCoding.decode(StringCoding.java:170) at java.lang.String.<init>(String.java:443) at java.lang.String.<init>(String.java:515) at org.ictclas4j.bean.Dictionary.load(Dictionary.java:102) at org.ictclas4j.bean.Dictionary.load(Dictionary.java:52) at org.ictclas4j.segment.PosTagger.<init>(PosTagger.java:39) at org.ictclas4j.segment.SegTag.<init>(SegTag.java:33) 没有支持GBK的编码包,这个好办,加载C:\\Java\\jdk1.6.0_18\\jre\\lib\\charsets.jar就可以了 测试代码修改如下 require 'rubygems' require 'rjb' root_ICTCLAS = "C:\\cygwin\\home\\Tachikoma\\workspace\\try\\ICTCLAS" root_jdk = "c:\\Java\\jdk1.6.0_18" Rjb::load(classpath = ".;#{root_ICTCLAS}\\bin;#{root_ICTCLAS}\\commons-lang-#2.5\\commons-lang-2.5.jar;C:\\Java\\jdk1.6.0_18\\jre\\lib\\charsets.jar" , [ "-Xbootclasspath:#{root_jdk}\\jre\\lib\\rt.jar" , "-Dsun.boot.library.path=#{root_jdk}\\jre\\bin" , "-Duser.dir=#{root_ICTCLAS}" ]) segtag_class = Rjb::import('org.ictclas4j.segment.SegTag') segtag = segtag_class.new_with_sig("I",1) seg_res = segtag.split("今天好累...") result = seg_res.getFinalResult() puts result 5. 终于,终于… $ ruby test.rb 今/g 天/g 好/g 累/v ../m
很好的结果 P.S. 如果看到的是乱码,记得把ruby的源文件按照utf-8的编码存储 6. 小感慨下 写完了才发现:有用的部分只是我的调试过程中很小的部分,实际调试的过程中,侵入了RJB的代码,ICTCLAS4J的代码,不得不花时间建立些小工具方便调试。 休息休息… 7.不得不承认,再过了一天后,我们的程序出了问题 问题大致是这样的:我们的程序只能对于"今天好累..."这样的短句分词,当涉及到"他从马上摔下来了“这样的例子,依然会看到NullPointerException这样的错误。 Hack进ICTCLAS的源程序,也没什么收获。只得对比Windows中调用ICTCLAS(通过segtag.bat脚本)和我们在Cygwin下调用ICTCLAS脚本的过程,在java选项中加入-verbose查看类载入过程(判断还是由于哪个类载入不正确或者Data文件夹下字典文件读取不正确造成的),没有发现特别的区别,只是charsets.jar也被作为bootclass载入了,于是修改测试代码中Rjb的载入部分如下:
Rjb::load(classpath = ".;#{root_ICTCLAS}\\bin;#{root_ICTCLAS}\\commons-lang-2.5\\commons-lang-2.5.jar" , [ "-Xbootclasspath:#{root_jdk}\\jre\\lib\\rt.jar;C:\\Java\\jdk1.6.0_18\\jre\\lib\\charsets.jar" , "-Dsun.boot.library.path=#{root_jdk}\\jre\\bin" , "-Duser.dir=#{root_ICTCLAS}" ]) 将charsets.jar也调入bootclass中,运行结果成功 这个错误的修正,也算是运气,实际并没有什么理论的依据,而且对于charsets.jar的载入顺序问题,整个机制并没有给出错误或警告
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论