再谈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来完成的().
再谈Contacts中姓氏多音字排序错误问题的更多相关文章
- Unity教程之再谈Unity中的优化技术
这是从 Unity教程之再谈Unity中的优化技术 这篇文章里提取出来的一部分,这篇文章让我学到了挺多可能我应该知道却还没知道的知识,写的挺好的 优化几何体 这一步主要是为了针对性能瓶颈中的”顶点 ...
- 再谈c++中的引用
在<从汇编看c++的引用和指针>一文中,虽然谈到了引用,但是只是为了将两者进行比较.这里将对引用做进一步的分析. 1 引用的实现方式 在介绍有关引用的c++书中,很多都说引用只是其引用变量 ...
- NET Core微服务之路:再谈分布式系统中一致性问题分析
前言 一致性:很多时候表现在IT系统中,通常在分布式系统中,必须(或最终)为多个节点的数据保持一致.世间万物,也有存在相同的特征或相似,比如儿时的双胞胎,一批工厂流水线的产品,当然,我们不去讨论非IT ...
- 再谈AR中的图像识别算法
之前在<浅谈移动平台创新玩法>简单的猜测了easyar中使用的图像识别算法,基于图片指纹的哈希算法的图片检索 .后再阿里引商大神的指点下,意识到图片检测只适用于静态图片的识别,只能做AR脱 ...
- 【一次面试】再谈javascript中的继承
前言 面向对象编程是每次面试必问的知识点,而前端js如何实现继承每次命中率高达80% 这不,近两天我们面试时候,同事就问道面试者此问题,但是,不论之前自己做的回答,还是面试者的回答,基本都不太令人满意 ...
- 再谈vim中多窗口的编辑
参考:http://blog.csdn.net/shuangde800/article/details/11430659 很好 鼠标在各个窗口间循环移动: ctrl+w+(小写的 hjkl), &qu ...
- 再谈机器学习中的归一化方法(Normalization Method)
机器学习.数据挖掘工作中,数据前期准备.数据预处理过程.特征提取等几个步骤几乎要花费数据工程师一半的工作时间.同时,数据预处理的效果也直接影响了后续模型能否有效的工作.然而,目前的大部分学术研究主要集 ...
- 再谈vim中多窗口的编辑 ctrl+w+H窗口位置最大化和互换等操作
参考:http://blog.csdn.net/shuangde800/article/details/11430659 很好 鼠标在各个窗口间循环移动: ctrl+w+(小写的 hjkl), &qu ...
- JVM系列之:再谈java中的safepoint
目录 safepoint是什么 safepoint的例子 线程什么时候会进入safepoint safepoint是怎么工作的 总结 safepoint是什么 java程序里面有很多很多的java线程 ...
随机推荐
- BZOJ5170: Fable 树状数组
Description 有这么一则传闻,O(nlogn)的排序发明之前,滋滋国的排序都是采用的冒泡排序.即使是冒泡排序,对当时的国民 来说也太复杂太难以理解,于是滋滋国出现了这样一个职业——排序使,收 ...
- 论文笔记之:Human-level control through deep reinforcement learning
Human-level control through deep reinforcement learning Nature 2015 Google DeepMind Abstract RL 理论 在 ...
- 01_Spark基础
1.1.Spark Ecosystem BlinkDB: 允许用户定义一个错误范围,BlinkDB将在用户给定的错误范围内,尽可能快的提供查询结果 1.2.Spark愿景 1.3.Spark简介 1) ...
- python2 安装scrapy出现错误提示解决办法~
首先:set STATICBUILD=true && pip install lxml 安装环境: windows7操作系统,已经正确安装python,pip. 使用pip功能安装Sc ...
- Android提高第九篇之GridView和SQLite实现分页表格
实现并封装一个SQL分页表格控件,不仅支持分页还是以表格的形式展示数据.先来看看本文程序运行的动画: 这个SQL分页表格控件主要分为“表格区”和“分页栏”这两部分,这两部分都是基于GridView实现 ...
- react notes
jsx 在JSX中嵌入用户输入是安全的,默认情况下, 在渲染之前, React DOM 会格式化(escapes) JSX中的所有值. 从而保证用户无法注入任何应用之外的代码. 在被渲染之前,所有的数 ...
- 最长的文件路径 Longest Absolute File Path
2018-07-30 22:05:52 问题描述: 问题求解: 本题个人感觉还是挺有意思的,题目要求的是最长的文件路径,其实是需要keep tracking路径长度,如果出现文件则需要进行比较,看是否 ...
- php 邮件发送利器 PHPMailer
php 自带的邮件发送函数已经弱到不能用了. PHPMailer非常的强大. 绝对是php里必须使用的程序. 下载地址: https://github.com/Synchro/PHPMailer 只要 ...
- Style、ControlTemplate 和 DataTemplate 触发器
本文摘要: 1:属性触发器: 2:数据触发器: 3:事件触发器: Style.ControlTemplate 和 DataTemplate 都有触发器集合. 属性触发器只检查W ...
- 1月4日编程基础hash
早上git加星了webapp的教程 > h = Hash.new('Go Fishing') => {} // 创建一个空hash,设定"Go Fishing&qu ...