说到中国人的名字,那就不得不考虑多音字的问题,比如'单',在作为姓氏时应该读作'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来完成的().

再谈Contacts中姓氏多音字排序错误问题的更多相关文章

  1. Unity教程之再谈Unity中的优化技术

    这是从 Unity教程之再谈Unity中的优化技术 这篇文章里提取出来的一部分,这篇文章让我学到了挺多可能我应该知道却还没知道的知识,写的挺好的 优化几何体   这一步主要是为了针对性能瓶颈中的”顶点 ...

  2. 再谈c++中的引用

    在<从汇编看c++的引用和指针>一文中,虽然谈到了引用,但是只是为了将两者进行比较.这里将对引用做进一步的分析. 1 引用的实现方式 在介绍有关引用的c++书中,很多都说引用只是其引用变量 ...

  3. NET Core微服务之路:再谈分布式系统中一致性问题分析

    前言 一致性:很多时候表现在IT系统中,通常在分布式系统中,必须(或最终)为多个节点的数据保持一致.世间万物,也有存在相同的特征或相似,比如儿时的双胞胎,一批工厂流水线的产品,当然,我们不去讨论非IT ...

  4. 再谈AR中的图像识别算法

    之前在<浅谈移动平台创新玩法>简单的猜测了easyar中使用的图像识别算法,基于图片指纹的哈希算法的图片检索 .后再阿里引商大神的指点下,意识到图片检测只适用于静态图片的识别,只能做AR脱 ...

  5. 【一次面试】再谈javascript中的继承

    前言 面向对象编程是每次面试必问的知识点,而前端js如何实现继承每次命中率高达80% 这不,近两天我们面试时候,同事就问道面试者此问题,但是,不论之前自己做的回答,还是面试者的回答,基本都不太令人满意 ...

  6. 再谈vim中多窗口的编辑

    参考:http://blog.csdn.net/shuangde800/article/details/11430659 很好 鼠标在各个窗口间循环移动: ctrl+w+(小写的 hjkl), &qu ...

  7. 再谈机器学习中的归一化方法(Normalization Method)

    机器学习.数据挖掘工作中,数据前期准备.数据预处理过程.特征提取等几个步骤几乎要花费数据工程师一半的工作时间.同时,数据预处理的效果也直接影响了后续模型能否有效的工作.然而,目前的大部分学术研究主要集 ...

  8. 再谈vim中多窗口的编辑 ctrl+w+H窗口位置最大化和互换等操作

    参考:http://blog.csdn.net/shuangde800/article/details/11430659 很好 鼠标在各个窗口间循环移动: ctrl+w+(小写的 hjkl), &qu ...

  9. JVM系列之:再谈java中的safepoint

    目录 safepoint是什么 safepoint的例子 线程什么时候会进入safepoint safepoint是怎么工作的 总结 safepoint是什么 java程序里面有很多很多的java线程 ...

随机推荐

  1. LeetCode——Maximum Binary Tree

    Question Given an integer array with no duplicates. A maximum tree building on this array is defined ...

  2. Java8的新特性,二进制序列转十进制数字

    package kata_007_二进制序列转十进制int; /** * java8 Lambda表达式转换binary序列->十进制数 */ import java.util.ArrayLis ...

  3. Vim打开文件中文乱码如何解决?

    今天想找一下之前的随机数组demo复习,在源文件src里用vim打开.java文件,中文出现乱码 vim也是,选项里没有直接选择设置utf-8之类的 查了下网上,http://easwy.com/bl ...

  4. Visual Studio 项目模板制作(三)

    前面,我们已经制作好了模板,然后放到相应的Template目录就可以在Visual Studio中使用 本篇,我们采用安装VSIX扩展的方式来安装模板,这种方式需要安装Visual Studio SD ...

  5. NS3 MyApp Class Reference

    官方文档:MyApp 可以在下面的几个例子找到: examples/tutorial/fifth.cc examples/tutorial/seventh.cc examples/tutorial/s ...

  6. BZOJ 1003: [ZJOI2006]物流运输(spfa+dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1003 题意: 思路: 首先用spfa计算一下任意两天之内的最短路,dis[a][b]表示的就是在第a ...

  7. mvc ---- ajax 提交过来的Json格式如何处理(解析)

    前台传过来的不是一个对象,而是一个Json字符串怎么办 ? 如: {","contents":"<p>lsdfjlsdjflsdf</p> ...

  8. React Native控件之Picker

    1. import React,{Component}from 'react'; import { AppRegistry, StyleSheet, Text, View, Picker, } fro ...

  9. 退出shell 脚本

    #!/bin/bash export TOP_PID=$$ trap 'exit 1' TERM exit_script(){ kill -s TERM $TOP_PID } echo "b ...

  10. Jenkins + Ant + Jmeter 对项目的接口进行CI持续集成的配置 外加发送邮件 sendEmail

    Step1:安装Jenkins,从指定git上拉代码[安装步骤忽略] Step2:在项目安装的linux server上安装Ant 和Jmeter,我都安装在了自己的目录上,如下图 Step3:编写b ...