再談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來完成的().

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM