android多音字排序,再谈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 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来完成的().

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值