Android切词工具——BreakIterator(1)

来源:互联网 发布:淘宝排名收费 编辑:程序博客网 时间:2024/06/07 07:01

本文介绍一下Android官方提供的切词工具BreakIterator。

1.关于切词

切词是一个常见的需求,对于中文更为重要,因为类似英文一样的以单词为中心的语言,以空格和标点符号为天然分隔符。但中文不一样,想要理解中文的准确含义,准确地切分词是第一步。例如,搜索的时候,如果输入是“看视频”,用户的意图显然是搜索视频,如果按照整句匹配,显然会欠召回。理想的情况应该是将“看视频”切成“看”和“视频”,并且识别出中心意图词是“视频”,进而主要搜索视频。当然,切词的准确性就很重要了,是一切的基础——如果切成“看视”和“频”,或者“看”“视”“频”,就适得其反了。

2.BreakIterator是个什么玩意?

Android官方SDK已经给出了切词工具BreakIterator,支持中文切词。目前Android SDK中同时存在两个BreakIterator:
java.text.BreakIterator
https://developer.android.com/reference/java/text/BreakIterator.html
android.icu.text.BreakIterator
https://developer.android.com/reference/android/icu/text/BreakIterator.html
前者API level 1,“根红苗正”。后者API level 24,从Android 7.0引入。其实二者同源。
二者用法基本相同,以前者为例,切一个句子,用法很简单友好:

 public static void main(String args[]) {      if (args.length == 1) {          String stringToExamine = args[0];          //print each word in order          BreakIterator boundary = BreakIterator.getWordInstance();          boundary.setText(stringToExamine);          printEachForward(boundary, stringToExamine);      } }     public static void printEachForward(BreakIterator boundary, String source) {         int start = boundary.first();         for (int end = boundary.next();              end != BreakIterator.DONE;              start = end, end = boundary.next()) {              System.out.println(source.substring(start,end));         }     }

(1)ICU和android.icu.text.BreakIterator
什么是ICU?我们可以去官网看看:http://site.icu-project.org/ 。ICU - International Components for Unicode,这是一个处理国际化统一码(Unicode)的开源项目,提供大量的自然语言文本处理功能,切词只是其中之一。同时提供c/c++(ICU4C)和Java版本(ICU4J)。从官网上的这段话可以看出ICU的愿景是提供跨平台的统一编码和国际化能力:
ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.
ICU目前最新的版本是59.1(20170414)。
android.icu.text,是Android 7.0将开源项目ICU引入了Android,并做了一些改进。android.icu.text.BreakIterator是其中一个重要的API。
(2)java.text.BreakIterator
从源代码看,java.text.BreakIterator是一个抽象类,由工厂方法getXXXInstance()提供实例:
Android 7.0以前:

    /**     * Returns a new instance of {@code BreakIterator} to iterate over     * word-breaks using the default locale.     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".     * @return a new instance of {@code BreakIterator} using the default locale.     */    public static BreakIterator getWordInstance() {        return getWordInstance(Locale.getDefault());    }    /**     * Returns a new instance of {@code BreakIterator} to iterate over     * word-breaks using the given locale.     */    public static BreakIterator getWordInstance(Locale locale) {        return new IcuIteratorWrapper(                com.ibm.icu.text.BreakIterator.getWordInstance(locale));    }

Android 7.0及以后:

    /**     * Returns a new <code>BreakIterator</code> instance     * for <a href="#word">word breaks</a>     * for the {@linkplain Locale#getDefault() default locale}.     *     * @return A break iterator for word breaks     */    public static BreakIterator getWordInstance() {        return getWordInstance(Locale.getDefault());    }    /**     * Returns a new <code>BreakIterator</code> instance     * for <a href="#word">word breaks</a>     * for the given locale.     *     * @param locale the desired locale     * @return A break iterator for word breaks     * @throws NullPointerException if <code>locale</code> is null     */    public static BreakIterator getWordInstance(Locale locale) {        return new IcuIteratorWrapper(                android.icu.text.BreakIterator.getWordInstance(locale));    }

哈哈,原来java.text.BreakIterator也是封装了ICU。Android果然是开源大杂烩啊。
Android 7.0开始实际上直接用android.icu.text.BreakIterator了,两者就是一回事了。
Android 7.0以前,是引入的包com.ibm.icu.text,从Android codebase来看,android.icu.text.BreakIterator位于
external/icu/icu4j/main/classes/core/src/com/ibm/icu/text/BreakIterator.java
看到实际上icu是作为一个external库,作为Android源代码的一部分而存在。external/icu包含icu4j和icu4c。

3.中文切词效果测试

下面测试一下切词效果。我目前的应用场景在Android 6以及下,所以测试java.text.BreakIterator。测试环境Android 6.0.1,测试代码如下:

package com.example.testicu;import android.text.TextUtils;import java.text.BreakIterator;import java.util.ArrayList;public class Util {    public static ArrayList<String> breakSentence(final String sentence) {        final ArrayList<String> result = new ArrayList<String>();        if (!TextUtils.isEmpty(sentence)) {            final BreakIterator boundary = BreakIterator.getWordInstance();            boundary.setText(sentence);            try {                int start = boundary.first();                for (int end = boundary.next();                     end != BreakIterator.DONE;                     start = end, end = boundary.next()) {                    String word = sentence.substring(start, end);                    if (!TextUtils.isEmpty(word)) {                        result.add(word);                    }                }            } catch (IndexOutOfBoundsException e) {                e.printStackTrace();                result.clear();            }        }        return result;    }}

(1)常规词短语

原始词 切词结果 看视频 看-视频 听音乐 听-音乐 看小说 看-小说 遥控器 遥控-器 逛商场 逛-商场

可以看到常规词效果尚可。

(2)比较新的专用名词(以APP名为例)和人名

原始词 切词结果 微信 微-信 微博 微-博 爱奇艺 爱-奇-艺 今日头条 今日-头条 勒布朗詹姆斯 勒-布朗-詹-姆-斯 迈克尔乔丹 迈-克-尔-乔-丹 张艺谋 张-艺-谋

新词和人名基本无能为力。

(3)切句子效果如何
随便找一些中文句子来测试:

测试1:
杨振宁,1922年10月1日出生于安徽合肥,现任香港中文大学讲座教授、清华大学教授、美国纽约州立大学石溪分校荣休教授[1] ,是中国科学院院士、美国国家科学院院士、台湾“中央研究院”院士、俄罗斯科学院院士、英国皇家学会会员,1957年获诺贝尔物理学奖;是中美关系松动后回中国探访的第一位华裔科学家,积极推动中美文化交流和中美人民的互相了解;在促进中美两国建交、中美人才交流和科技合作等方面,做出了重大贡献。
结果1:
杨-振-宁-,-1922-年-10-月-1-日出生-于-安徽-合肥-,-现任-香港-中文-大学-讲座-教授-、-清华大学-教授-、-美国-纽约-州立-大学-石-溪-分校-荣-休-教授-[-1-]- - -,-是-中国-科-学院-院士-、-美国-国家-科-学院-院士-、-台湾-“-中央研究院-”-院士-、-俄罗斯-科-学院-院士-、-英国-皇家-学会-会员-,-1957-年-获-诺贝尔-物理-学-奖-;-是-中美关系-松-动-后-回-中国-探访-的-第-一位-华裔-科学-家-,-积极-推动-中美-文化-交流-和-中美-人民-的-互相-了解-;-在-促进-中美-两国-建交-、-中美-人才-交流-和-科技-合作-等-方面-,-做出-了-重大-贡献-。
测试2:
这首《飞鸟各投林》是《红楼梦》十二钗曲里的收尾曲,最早出现在第五回的时候,是以食尽鸟飞、唯余白地的悲凉图景,预示贾府未来子孙流散、十二钗花落断肠的惨象。当时林黛玉还未进大观园,这曲子就已为四大家族的衰亡预先敲起了丧钟。
结果2:
这-首-《-飞鸟-各-投-林-》-是-《-红楼梦-》-十二-钗-曲-里-的-收尾-曲-,-最早-出现-在-第五-回-的-时候-,-是以-食尽-鸟-飞-、-唯-余白-地-的-悲-凉-图-景-,-预示-贾-府-未来-子孙-流散-、-十二-钗-花落-断肠-的-惨-象-。-当时-林黛玉-还-未进-大-观-园-,-这-曲子-就-已-为-四大-家族-的-衰亡-预先-敲起-了-丧钟-。
测试3:
什么是ICU?我们可以去官网看看:http://site.icu-project.org/ 。ICU - International Components for Unicode,这是一个处理国际化统一码(Unicode)的开源项目,提供大量的自然语言文本处理功能,切词只是其中之一。同时提供c/c++(ICU4C)和Java版本(ICU4J)。从官网上的这段话可以看出ICU的愿景是提供跨平台的统一编码和国际化能力
结果3:
什么-是-ICU-?-我们-可以-去-官-网-看看-:-http-:-/-/-site.icu—project.org-/- -。-ICU- — -International- -Components- -for- -Unicode-,-这-是-一个-处理-国际-化-统一-码-(-Unicode-)-的-开-源-项目-,-提供-大量-的-自然-语言-文本-处理-功能-,-切-词-只是-其中-之一-。-同时-提供-c-/-c-+-+-(-ICU4C-)-和-Java-版本-(-ICU4J-)-。-从-官-网上-的-这-段-话-可以-看出-ICU-的-愿景-是-提供-跨-平台-的-统一-编码-和-国际-化-能力

可以看到对于长句子存在专用名词较差、切词过细的问题。

综合来看,对于常规的、短句子尚可一用。

原创粉丝点击