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

android多音字排序,再谈Contacts中姓氏多音字排序错误问题相关推荐

  1. 如何解决Contacts中的多音字排序错误问题

    在本文中将给出两个解决多音字排序错误的解决方案. 以多音字曾为例,作为姓氏是读作Zeng,而android中却按Ceng来对其排序. 方法一:修改base中external/icu4c/data/co ...

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

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

  3. java 中的排序_浅谈java中常见的排序

    浅谈java中常见的排序 学过java的人都知道,排序这一部分初次接触感觉还是有点难以理解,很多地方也会用到.然而,在java中常见的排序方法:冒泡排序,选择排序,插入排序等等.下面就让我们一起揭开他 ...

  4. mysql 关闭in自动排序,mysql排序语句_mysql中的in排序 mysql按in中顺序来排序

    摘要 腾兴网为您分享:mysql中的in排序 mysql按in中顺序来排序,易订货,虚拟按键,享家,顺丰小哥等软件知识,以及方正证券小方,音基100,dwg转dwf,酷狗游戏盒,聊天宝客服聊天,kin ...

  5. 数据库中自定义排序规则,Mysql中自定义字段排序规则,Oracle中自定义字段排序规则,decode函数的用法,field函数的用法

    数据库中自定义排序 场景:有一张banner表,表中有一个status字段,有0, 1, 2三个状态位,我想要 1,0,2的自定义排序(这里是重点),然后再进行之上对sequence字段进行二次排序( ...

  6. python五种常见的排序方法是_python中序列的排序,sorted方法、reversed方法的使用...

    简介 INTRODUCTION 包括字典排序.列表排序.升序.降序.逆序 一.基础概念 我们知道python中的内建序列包括字典.列表.元组.字符串等,序列是python中最基本的数据结构. 列表.元 ...

  7. mysql先排序再分组筛选_mysql 怎样先排序再分组

    权游游牧族:众所周知!一句SqL语句不能先排序再分组.所以这里给出几个案例 --表结构-- create table `shop` ( `id` int (10) PRIMARY KEY, `shop ...

  8. java list 元素排序_对arraylist中元素进行排序实例代码

    rrayList中的元素进行排序,主要考查的是对util包中的Comparator接口和Collections类的使用. 实现Comparator接口必须实现compare方法,自己可以去看API帮助 ...

  9. mybatis多字段排序_解决mybatis中order by排序无效问题

    1.#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #{user_id},如果传入的值是111,那么解析成sql时的值为order by "111&qu ...

  10. mysql 如何自定义排序_在MySQL中实现自定义排序顺序

    要在MySQL中实现自定义排序顺序,您需要使用ORDER BY FIELD().让我们首先创建一个表-create table DemoTable -> ( -> Designation  ...

最新文章

  1. 当表格列数太多时,怎么实现表格的横向滚动
  2. 《区块链原理、设计与应用》一3.3 征信和权属管理
  3. java system.runfinalization()_Android中缓存理解(一)
  4. rman备份恢复总结
  5. 《大道至简》第二章 读后感
  6. 33条C#、.Net经典面试题目及答案
  7. 几个有趣的python技巧
  8. 疯狂的ASP.NET系列-第一篇:啥是ASP.NET
  9. linux 带ifdef运行程序_如何让linux的一段程序代码进入内核态运行
  10. zoj3494BCD Code(ac自动机+数位dp)
  11. 【Elasticsearch】Elasticsearch底层系列之Shard Allocation机制
  12. 百面机器学习—5.SVM要点总结
  13. python int占几个字节_int占几个字节(c语言)?
  14. bochs模拟器创建映像文件 、写入文件并启动
  15. 使用sklearn出现错误:ValueError: Expected 2D array, got 1D array instead 解决方法
  16. 某60终端安全管理系统前台SQL注入漏洞复现
  17. 同源性 相似性 一致性
  18. 3842的充电器原理
  19. 西游记中孙悟空大闹天宫时玉帝为什么不亲自出手?
  20. 青年论坛:谈判的情感力量

热门文章

  1. Vue异步获取数据后初始化数据不能及时更新
  2. 字符串常量池(StringTable)总结
  3. Ubuntu各文件夹功能说明
  4. 对Javascript异步执行的理解
  5. 【Go语言】I/O专题
  6. 压缩与解压2---文件的压缩
  7. EditText有焦点(focusable为true)阻止输入法弹出
  8. \r\n的来历与用法
  9. 【原译】一个可定制的WPF任务对话框
  10. php多克,php对象克隆