zoukankan      html  css  js  c++  java
  • 再谈Contacts中姓氏多音字排序错误问题

    说到中国人的名字,那就不得不考虑多音字的问题,比如'单',在作为姓氏时应该读作'shan'而不是'dan'.但是在Contacts程序中却使用的是'D'来作为bucket label!
    这是为什么?如何解决这种多音字姓氏的问题?

    从4.3版本开始,HanziToPinyin.java(ContactsProvider中)改为直接调用ICU的Transliterator来对汉字进行transliterate(详见类中mPinyinTransliterator变量的使用).我们知道,ICU中的Han_Latin_Names.txt中保存了一些汉字在作为姓氏时的读音,如果在创建Transliterator对象时使用Han-Latin/Names作为id(可参考mPinyinTransliterator变量的初始化),将可以正确的获得汉字作为姓氏时的读音(仅限于Han_Latin_Names.txt中包含的汉字).也就是说,HanziToPinyin这个类在处理作为姓氏的多音字时是可以获得正确获得其读音的.如在使用HanziToPinyin获取'单田芳'的读音为'shan tian fang'.就算这样姓名为'单田芳'的联系人依然被排在'D'下面!这是为什么呢?
    通过解析代码可以发现,联系人排在哪个字母下面是由raw_contacts表中的phonebook_label的值来决定的,而数据库中phonebook_label的值确实是'D',主要是因为在获得phonebook_label时使用的是AlphabeticIndex$ImmutableIndex的getBucketLabel函数,而这个函数是没有对姓氏多音字做任何特殊处理的,所以最后得到的是'D'(phonebook_label的处理流程见附一).

    目前,如果想比较省力的解决这个问题,可以在获取phonebook_label时避免通过使用AlphabeticIndex$ImmutableIndex的getBucketLabel函数来获取,而是改为用HanziToPinyin去获得sortKeyPrimary的第一个字符的拼音(sortKeyAlternative暂不考虑).

    贴一下代码修改(基于4.4.4_r2)
    -----------------------------------------------------------------------------
    --- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
    +++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
    @@ -78,6 +78,7 @@ import android.text.util.Rfc822Tokenizer;
     import android.util.Log;
     
     import com.android.common.content.SyncStateContentProviderHelper;
    +import com.android.providers.contacts.HanziToPinyin.Token;
     import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
     import com.android.providers.contacts.database.ContactsTableUtil;
     import com.android.providers.contacts.database.DeletedContactsTableUtil;
    @@ -85,6 +86,7 @@ import com.android.providers.contacts.database.MoreDatabaseUtils;
     import com.android.providers.contacts.util.NeededForTesting;
     import com.google.android.collect.Sets;
     
    +import java.util.ArrayList;
     import java.util.HashMap;
     import java.util.Locale;
     import java.util.Set;
    @@ -5388,8 +5390,25 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper {
             ContactLocaleUtils localeUtils = ContactLocaleUtils.getInstance();
     
             if (sortKeyPrimary != null) {
    -            phonebookBucketPrimary = localeUtils.getBucketIndex(sortKeyPrimary);
    -            phonebookLabelPrimary = localeUtils.getBucketLabel(phonebookBucketPrimary);
    +            boolean flag = false;
    +            if (displayNameStyle == FullNameStyle.CHINESE
    +                    && HanziToPinyin.getInstance().hasChineseTransliterator()) {
    +                String target = sortKeyPrimary.substring(0, 1);
    +                ArrayList<Token> tokens = HanziToPinyin.getInstance().get(target);
    +                if (tokens != null && tokens.size() > 0) {
    +                    char label = tokens.get(0).target.charAt(0);
    +                    if (label >= 'A' && label <= 'Z') {
    +                        phonebookLabelPrimary = String.valueOf(label);
    +                        phonebookBucketPrimary = localeUtils.getBucketIndex(phonebookLabelPrimary);
    +                        flag = true;
    +                    }
    +                }
    +            }
    +
    +            if (!flag) {
    +                phonebookBucketPrimary = localeUtils.getBucketIndex(sortKeyPrimary);
    +                phonebookLabelPrimary = localeUtils.getBucketLabel(phonebookBucketPrimary);
    +            }
             }
             if (sortKeyAlternative != null) {
                 phonebookBucketAlternative = localeUtils.getBucketIndex(sortKeyAlternative);

    -----------------------------------------------------------------------------
    通过上面的分析可以发现一个问题,那就是在Contacts主页面用'dan tian fang'搜索联系人时是搜不到的,只能用'shan tian fang'来搜索,但是在显示时确是将该联系人放在了'D'分组下面!根本原因就是NameLookupBuilder在调用 appendNameShorthandLookup时实际上使用了HanziToPinyin来获取读音,这时得到的是作为姓氏时的读音,而 phonebook_label是使用AlphabeticIndex$ImmutableIndex的getBucketLabel函数来获取的,而它 没有对姓氏多音字做任何特殊处理,这就导致了前面说的问题.
    另外,用HanziToPinyin的一个问题是所有的可作为姓氏的汉字的读音都是姓氏的读音,如'单位单'的拼音是'shan wei shan'.如何解决这个问题呢?其实现有条件下没有一个好的办法(加词库的方法除外),只能尽量规避.我的方法是中文情况下名字中的第一个汉字作为姓氏去获取读音(使用Han-Latin/Names; Latin-Ascii; Any-Upper创建的Transliterator对象),而其它汉字则作为普通汉字去获取读音(使用Han-Latin; Latin-Ascii; Any-Upper创建的Transliterator对象,需在HanziToPinyin中再新建一个Transliterator对象).

    附一
    raw_contacts表中的phonebook_label的获取流程:
    raw_contacts表中的phonebook_label是通过调用ContactsDatabaseHelper的updateRawContactDisplayName函数来完成插入/更新的.使用的是phonebookLabelPrimary变量的值.而phonebookLabelPrimary是ContactLocaleUtils中getBucketLabel获得的,getBucketLabel中实际调用的是ICU中ImmutableIndex的getBucketLabel来完成的().

  • 相关阅读:
    分布式框架服务调用超时设计与实现
    分布式框架灰度发布实现
    写给自己的 SOA 和 RPC 理解
    Java 基础【19】代理
    Java 基础【18】 反射与内省
    Spring HttpInvoker 从实战到源码追溯
    Lombok 使用攻略
    Guava Preconditions 工具参数前置校验
    CAS 单点登录【2】自定义用户验证
    Hibernate 离线对象构建通用查询
  • 原文地址:https://www.cnblogs.com/Lefter/p/4016004.html
Copyright © 2011-2022 走看看