发现Android自带的icu4c可以直接使用,不需要自己编译它。它的JNI接口可以用java.text包下的类间接调用。
我感兴趣的是icu4c的范围分析功能,即所谓的分词,例如,可以用java.text.BreakIterator实现日文和中文粗略分词(前提是需要事先指定其语言区域,不过后来实测发现日文的分词效果并不如专门的分词库那么好)。官方文档中有一个使用示例,用起来也非常方便:
package com.iteye.weimingtom.icutest; import java.text.BreakIterator; import java.util.Locale; import android.app.Activity; import android.os.Bundle; public class ICUTestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final String testStr = "残忍で破壊的な性格がチャームポイントな本作の主人公[6][7]。" + "真尋にひと目惚れし、それ以来、" + "下心を隠そうともせず猛アタックを続けている。"; System.out.println("日文范围划分"); test(Locale.JAPAN, testStr); System.out.println("中文范围划分"); test(Locale.CHINA, testStr); /* 08-15 19:05:24.825: I/System.out(9011): 日文范围划分 08-15 19:05:24.835: I/System.out(9011): 残忍 08-15 19:05:24.835: I/System.out(9011): で 08-15 19:05:24.845: I/System.out(9011): 破壊的 08-15 19:05:24.845: I/System.out(9011): な 08-15 19:05:24.845: I/System.out(9011): 性格 08-15 19:05:24.845: I/System.out(9011): が 08-15 19:05:24.845: I/System.out(9011): チャームポイント 08-15 19:05:24.845: I/System.out(9011): な 08-15 19:05:24.845: I/System.out(9011): 本作 08-15 19:05:24.845: I/System.out(9011): の 08-15 19:05:24.845: I/System.out(9011): 主人公 08-15 19:05:24.845: I/System.out(9011): [ 08-15 19:05:24.845: I/System.out(9011): 6 08-15 19:05:24.845: I/System.out(9011): ] 08-15 19:05:24.855: I/System.out(9011): [ 08-15 19:05:24.855: I/System.out(9011): 7 08-15 19:05:24.855: I/System.out(9011): ] 08-15 19:05:24.855: I/System.out(9011): 。 08-15 19:05:24.855: I/System.out(9011): 真尋 08-15 19:05:24.855: I/System.out(9011): にひと 08-15 19:05:24.855: I/System.out(9011): 目惚 08-15 19:05:24.855: I/System.out(9011): れし 08-15 19:05:24.865: I/System.out(9011): 、 08-15 19:05:24.865: I/System.out(9011): それ 08-15 19:05:24.865: I/System.out(9011): 以来 08-15 19:05:24.865: I/System.out(9011): 、 08-15 19:05:24.865: I/System.out(9011): 下心 08-15 19:05:24.865: I/System.out(9011): を 08-15 19:05:24.865: I/System.out(9011): 隠 08-15 19:05:24.865: I/System.out(9011): そうともせず 08-15 19:05:24.865: I/System.out(9011): 猛 08-15 19:05:24.865: I/System.out(9011): アタック 08-15 19:05:24.865: I/System.out(9011): を 08-15 19:05:24.865: I/System.out(9011): 続 08-15 19:05:24.865: I/System.out(9011): けている 08-15 19:05:24.865: I/System.out(9011): 。 08-15 19:05:24.865: I/System.out(9011): 中文范围划分 08-15 19:05:24.885: I/System.out(9011): 残 08-15 19:05:24.885: I/System.out(9011): 忍 08-15 19:05:24.885: I/System.out(9011): で 08-15 19:05:24.885: I/System.out(9011): 破 08-15 19:05:24.885: I/System.out(9011): 壊 08-15 19:05:24.885: I/System.out(9011): 的 08-15 19:05:24.885: I/System.out(9011): な 08-15 19:05:24.885: I/System.out(9011): 性 08-15 19:05:24.885: I/System.out(9011): 格 08-15 19:05:24.885: I/System.out(9011): が 08-15 19:05:24.885: I/System.out(9011): チャームポイント 08-15 19:05:24.885: I/System.out(9011): な 08-15 19:05:24.885: I/System.out(9011): 本 08-15 19:05:24.885: I/System.out(9011): 作 08-15 19:05:24.885: I/System.out(9011): の 08-15 19:05:24.885: I/System.out(9011): 主 08-15 19:05:24.885: I/System.out(9011): 人 08-15 19:05:24.885: I/System.out(9011): 公 08-15 19:05:24.885: I/System.out(9011): [ 08-15 19:05:24.885: I/System.out(9011): 6 08-15 19:05:24.885: I/System.out(9011): ] 08-15 19:05:24.885: I/System.out(9011): [ 08-15 19:05:24.885: I/System.out(9011): 7 08-15 19:05:24.885: I/System.out(9011): ] 08-15 19:05:24.885: I/System.out(9011): 。 08-15 19:05:24.885: I/System.out(9011): 真 08-15 19:05:24.885: I/System.out(9011): 尋 08-15 19:05:24.885: I/System.out(9011): に 08-15 19:05:24.885: I/System.out(9011): ひ 08-15 19:05:24.885: I/System.out(9011): と 08-15 19:05:24.885: I/System.out(9011): 目 08-15 19:05:24.895: I/System.out(9011): 惚 08-15 19:05:24.895: I/System.out(9011): れ 08-15 19:05:24.895: I/System.out(9011): し 08-15 19:05:24.895: I/System.out(9011): 、 08-15 19:05:24.895: I/System.out(9011): そ 08-15 19:05:24.895: I/System.out(9011): れ 08-15 19:05:24.895: I/System.out(9011): 以 08-15 19:05:24.905: I/System.out(9011): 来 08-15 19:05:24.905: I/System.out(9011): 、 08-15 19:05:24.905: I/System.out(9011): 下 08-15 19:05:24.905: I/System.out(9011): 心 08-15 19:05:24.905: I/System.out(9011): を 08-15 19:05:24.905: I/System.out(9011): 隠 08-15 19:05:24.905: I/System.out(9011): そ 08-15 19:05:24.905: I/System.out(9011): う 08-15 19:05:24.905: I/System.out(9011): と 08-15 19:05:24.905: I/System.out(9011): も 08-15 19:05:24.905: I/System.out(9011): せ 08-15 19:05:24.905: I/System.out(9011): ず 08-15 19:05:24.905: I/System.out(9011): 猛 08-15 19:05:24.905: I/System.out(9011): アタック 08-15 19:05:24.905: I/System.out(9011): を 08-15 19:05:24.905: I/System.out(9011): 続 08-15 19:05:24.905: I/System.out(9011): け 08-15 19:05:24.905: I/System.out(9011): て 08-15 19:05:24.915: I/System.out(9011): い 08-15 19:05:24.915: I/System.out(9011): る 08-15 19:05:24.915: I/System.out(9011): 。 */ } /** * @see http://developer.android.com/reference/java/text/BreakIterator.html * @param where * @param stringToExamine */ private static void test(Locale where, String stringToExamine) { BreakIterator boundary = BreakIterator.getWordInstance(where); boundary.setText(stringToExamine); int start = boundary.first(); for (int end = boundary.next(); end != BreakIterator.DONE; start = end, end = boundary.next()) { System.out.println(stringToExamine.substring(start, end)); } } }
PS:可能缺少一些区域,需要事先作判断。
boolean hasJapanLocal = false; Locale[] locales = BreakIterator.getAvailableLocales(); if (locales != null) { for (Locale locale : locales) { if (D) { Log.d(TAG, "locale: " + locale.toString()); } if (locale != null && locale.equals(Locale.JAPAN)) { hasJapanLocal = true; break; } } }
参考资料:
1. Android官方文档
http://developer.android.com/reference/java/text/BreakIterator.html
2. icu4c的官方文档
http://userguide.icu-project.org/boundaryanalysis
3. Android源代码中的测试代码
4. chrome使用的开源工程介绍