android功能模块之通讯模块七分析

访客 阅读:250 2021-04-01 00:24:19 评论:0

Android通讯录模糊匹配搜索实现(号码、首字母、简拼、全拼)


2013年12月10日
工作记录
小巫在工作中碰到一个需求,要求实现通讯录联系人的搜索,获取联系人的方式有好几种,我都有点混乱了,下面提供我最近用的一种,看起来还算比较简洁的,它是根据mimetypes表来查的。

  1. // 查询所有联系人的姓名,电话,邮箱  
  2.   
  3. public ArrayList<Contact> loadContacts() throws Exception {  
  4.   
  5.     Uri uri = Uri.parse("content://com.android.contacts/contacts");  
  6.   
  7.     ContentResolver resolver = this.getContentResolver();  
  8.   
  9.     Cursor cursor = resolver.query(uri, new String[] { "_id" }, nullnull,  
  10.             null);  
  11.     ArrayList<Contact> contacts = new ArrayList<Contact>();  
  12.     while (cursor.moveToNext()) {  
  13.   
  14.         Contact contact = new Contact();  
  15.         int contractID = cursor.getInt(0);  
  16.   
  17.         StringBuilder sb = new StringBuilder("contractID=");  
  18.   
  19.         contact.setId(String.valueOf(contractID));  
  20.         sb.append(contractID);  
  21.   
  22.         uri = Uri.parse("content://com.android.contacts/contacts/"  
  23.                 + contractID + "/data");  
  24.   
  25.         Cursor cursor1 = resolver.query(uri, new String[] { "mimetype",  
  26.                 "data1""data2" }, nullnullnull);  
  27.   
  28.         while (cursor1.moveToNext()) {  
  29.   
  30.             String data1 = cursor1.getString(cursor1  
  31.                     .getColumnIndex("data1"));  
  32.   
  33.             String mimeType = cursor1.getString(cursor1  
  34.                     .getColumnIndex("mimetype"));  
  35.   
  36.             if ("vnd.android.cursor.item/name".equals(mimeType)) { // 是姓名  
  37.                 contact.setName(data1);  
  38.                 sb.append(",name=" + data1);  
  39.   
  40.             } else if ("vnd.android.cursor.item/email_v2".equals(mimeType)) { // 邮箱  
  41.                 if (!TextUtils.isEmpty(data1)) {  
  42.                     contact.setEmail(data1);  
  43.                 }  
  44.                 contacts.add(contact);  
  45.                 sb.append(",email=" + data1);  
  46.   
  47.             } else if ("vnd.android.cursor.item/phone_v2".equals(mimeType)) { // 手机  
  48.                 contact.setNumber(data1.replaceAll("-"""));  
  49.                 sb.append(",phone=" + data1);  
  50.             }  
  51.   
  52.         }  
  53.         contacts.add(contact);  
  54.         cursor1.close();  
  55.   
  56.         Log.i("wwj", sb.toString());  
  57.   
  58.     }  
  59.   
  60.     cursor.close();  
  61.     return contacts;  
  62.   
  63. }  
	// 查询所有联系人的姓名,电话,邮箱 
 
	public ArrayList<Contact> loadContacts() throws Exception { 
 
		Uri uri = Uri.parse("content://com.android.contacts/contacts"); 
 
		ContentResolver resolver = this.getContentResolver(); 
 
		Cursor cursor = resolver.query(uri, new String[] { "_id" }, null, null, 
				null); 
		ArrayList<Contact> contacts = new ArrayList<Contact>(); 
		while (cursor.moveToNext()) { 
 
			Contact contact = new Contact(); 
			int contractID = cursor.getInt(0); 
 
			StringBuilder sb = new StringBuilder("contractID="); 
 
			contact.setId(String.valueOf(contractID)); 
			sb.append(contractID); 
 
			uri = Uri.parse("content://com.android.contacts/contacts/" 
					+ contractID + "/data"); 
 
			Cursor cursor1 = resolver.query(uri, new String[] { "mimetype", 
					"data1", "data2" }, null, null, null); 
 
			while (cursor1.moveToNext()) { 
 
				String data1 = cursor1.getString(cursor1 
						.getColumnIndex("data1")); 
 
				String mimeType = cursor1.getString(cursor1 
						.getColumnIndex("mimetype")); 
 
				if ("vnd.android.cursor.item/name".equals(mimeType)) { // 是姓名 
					contact.setName(data1); 
					sb.append(",name=" + data1); 
 
				} else if ("vnd.android.cursor.item/email_v2".equals(mimeType)) { // 邮箱 
					if (!TextUtils.isEmpty(data1)) { 
						contact.setEmail(data1); 
					} 
					contacts.add(contact); 
					sb.append(",email=" + data1); 
 
				} else if ("vnd.android.cursor.item/phone_v2".equals(mimeType)) { // 手机 
					contact.setNumber(data1.replaceAll("-", "")); 
					sb.append(",phone=" + data1); 
				} 
 
			} 
			contacts.add(contact); 
			cursor1.close(); 
 
			Log.i("wwj", sb.toString()); 
 
		} 
 
		cursor.close(); 
		return contacts; 
 
	}




关于模糊匹配,我真的有点头大,我想到的是用正则表达式来做,但需要用到第三方类库pinyin4j.jar,我试了一下,效率都点低,明显感觉有点慢了,假如你的通讯录的量比较大,用这个来做确实不合时宜,或许可以进行优化的地方。


定义一个工具类
  1. package com.search;  
  2.   
  3. import net.sourceforge.pinyin4j.PinyinHelper;  
  4. import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;  
  5. import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;  
  6. import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;  
  7. import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;  
  8. import android.provider.ContactsContract.CommonDataKinds.Phone;  
  9. import android.text.TextUtils;  
  10.   
  11. public class BaseUtil {  
  12.   
  13.     public final static String[] PHONES_PROJECTION = new String[] {  
  14.             Phone.DISPLAY_NAME, Phone.NUMBER };  
  15.   
  16.     public static String STRS[] = { """""[abc]""[def]""[ghi]""[jkl]",  
  17.             "[mno]""[pqrs]""[tuv]""[wxyz]" };  
  18.   
  19.     /** 
  20.      * 将字符串中的中文转化为拼音,其他字符不变 
  21.      *  
  22.      * @param inputString 
  23.      * @return 
  24.      */  
  25.     public static String getPingYin(String inputString) {  
  26.         if (TextUtils.isEmpty(inputString)) {  
  27.             return "";  
  28.         }  
  29.         HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();  
  30.         format.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
  31.         format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
  32.         format.setVCharType(HanyuPinyinVCharType.WITH_V);  
  33.   
  34.         char[] input = inputString.trim().toCharArray();  
  35.         String output = "";  
  36.   
  37.         try {  
  38.             for (int i = 0; i < input.length; i++) {  
  39.                 if (java.lang.Character.toString(input[i]).matches(  
  40.                         "[\\u4E00-\\u9FA5]+")) {  
  41.                     String[] temp = PinyinHelper.toHanyuPinyinStringArray(  
  42.                             input[i], format);  
  43.                     if (temp == null || TextUtils.isEmpty(temp[0])) {  
  44.                         continue;  
  45.                     }  
  46.                     output += temp[0].replaceFirst(temp[0].substring(01),  
  47.                             temp[0].substring(01).toUpperCase());  
  48.                 } else  
  49.                     output += java.lang.Character.toString(input[i]);  
  50.             }  
  51.         } catch (Exception e) {  
  52.             e.printStackTrace();  
  53.         }  
  54.         return output;  
  55.     }  
  56.   
  57. }  
package com.search; 
 
import net.sourceforge.pinyin4j.PinyinHelper; 
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; 
import android.provider.ContactsContract.CommonDataKinds.Phone; 
import android.text.TextUtils; 
 
public class BaseUtil { 
 
	public final static String[] PHONES_PROJECTION = new String[] { 
			Phone.DISPLAY_NAME, Phone.NUMBER }; 
 
	public static String STRS[] = { "", "", "[abc]", "[def]", "[ghi]", "[jkl]", 
			"[mno]", "[pqrs]", "[tuv]", "[wxyz]" }; 
 
	/** 
	 * 将字符串中的中文转化为拼音,其他字符不变 
	 *  
	 * @param inputString 
	 * @return 
	 */ 
	public static String getPingYin(String inputString) { 
		if (TextUtils.isEmpty(inputString)) { 
			return ""; 
		} 
		HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); 
		format.setCaseType(HanyuPinyinCaseType.LOWERCASE); 
		format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 
		format.setVCharType(HanyuPinyinVCharType.WITH_V); 
 
		char[] input = inputString.trim().toCharArray(); 
		String output = ""; 
 
		try { 
			for (int i = 0; i < input.length; i++) { 
				if (java.lang.Character.toString(input[i]).matches( 
						"[\\u4E00-\\u9FA5]+")) { 
					String[] temp = PinyinHelper.toHanyuPinyinStringArray( 
							input[i], format); 
					if (temp == null || TextUtils.isEmpty(temp[0])) { 
						continue; 
					} 
					output += temp[0].replaceFirst(temp[0].substring(0, 1), 
							temp[0].substring(0, 1).toUpperCase()); 
				} else 
					output += java.lang.Character.toString(input[i]); 
			} 
		} catch (Exception e) { 
			e.printStackTrace(); 
		} 
		return output; 
	} 
 
} 

  1. /** 
  2.  * 按号码-拼音搜索联系人 
  3.  * @param str 
  4.  */  
  5. public void search(String str){  
  6.     contactList.clear();  
  7.     //如果搜索条件以0 1 +开头则按号码搜索  
  8.     if(str.toString().startsWith("0") || str.toString().startsWith("1")  
  9.              || str.toString().startsWith("+")){  
  10.         for(Model model : allContactList){  
  11.             if(model.telnum.contains(str)){  
  12.                 model.group = str;  
  13.                 contactList.add(model);  
  14.             }  
  15.         }  
  16.         adapter.refresh(contactList, false);  
  17.         return;  
  18.     }  
  19.     StringBuffer sb = new StringBuffer();  
  20.     //获取每一个数字对应的字母列表并以'-'隔开  
  21.     for(int i = 0; i < str.length(); i++){  
  22.         sb.append((str.charAt(i) <= '9' && str.charAt(i) >= '0')  
  23.                 ? BaseUtil.STRS[str.charAt(i) - '0'] : str.charAt(i));  
  24.         if(i != str.length() - 1){  
  25.             sb.append("-");  
  26.         }  
  27.     }  
  28.       
  29.     for(Model model : allContactList){  
  30.         if(contains(sb.toString(), model, str)){  
  31.             contactList.add(model);  
  32.         } else if(model.telnum.contains(str)){  
  33.             model.group = str;  
  34.             contactList.add(model);  
  35.         }  
  36.     }  
  37.     adapter.refresh(contactList, false);  
  38.    }  
  39.   
  40. /** 
  41.  * 根据拼音搜索 
  42.  * @param str           正则表达式 
  43.  * @param pyName        拼音 
  44.  * @param isIncludsive  搜索条件是否大于6个字符 
  45.  * @return 
  46.  */  
  47. public boolean contains(String str, Model model, String search){  
  48.     if(TextUtils.isEmpty(model.pyname)){  
  49.         return false;  
  50.     }  
  51.     model.group = "";  
  52.     //搜索条件大于6个字符将不按拼音首字母查询  
  53.     if(search.length() < 6){  
  54.         //根据首字母进行模糊查询  
  55.         Pattern pattern = Pattern.compile("^" + str.toUpperCase().replace("-""[*+#a-z]*"));  
  56.         Matcher matcher = pattern.matcher(model.pyname);  
  57.           
  58.         if(matcher.find()){  
  59.             String tempStr = matcher.group();  
  60.             for(int i = 0; i < tempStr.length(); i++){  
  61.                 if(tempStr.charAt(i) >= 'A' && tempStr.charAt(i) <= 'Z'){  
  62.                     model.group += tempStr.charAt(i);  
  63.                 }  
  64.             }  
  65.             return true;  
  66.         }  
  67.     }  
  68.       
  69.     //根据全拼查询  
  70.     Pattern pattern = Pattern.compile(str.replace("-"""), Pattern.CASE_INSENSITIVE);  
  71.     Matcher matcher = pattern.matcher(model.pyname);  
  72.     boolean flag = matcher.find();  
  73.     if(flag){  
  74.         model.group = matcher.group();  
  75.     }  
  76.     return flag;  
  77. }  
	/** 
	 * 按号码-拼音搜索联系人 
	 * @param str 
	 */ 
	public void search(String str){ 
		contactList.clear(); 
		//如果搜索条件以0 1 +开头则按号码搜索 
		if(str.toString().startsWith("0") || str.toString().startsWith("1") 
				 || str.toString().startsWith("+")){ 
			for(Model model : allContactList){ 
				if(model.telnum.contains(str)){ 
					model.group = str; 
					contactList.add(model); 
				} 
			} 
			adapter.refresh(contactList, false); 
			return; 
		} 
		StringBuffer sb = new StringBuffer(); 
		//获取每一个数字对应的字母列表并以'-'隔开 
		for(int i = 0; i < str.length(); i++){ 
			sb.append((str.charAt(i) <= '9' && str.charAt(i) >= '0') 
					? BaseUtil.STRS[str.charAt(i) - '0'] : str.charAt(i)); 
			if(i != str.length() - 1){ 
				sb.append("-"); 
			} 
		} 
		 
		for(Model model : allContactList){ 
			if(contains(sb.toString(), model, str)){ 
				contactList.add(model); 
			} else if(model.telnum.contains(str)){ 
				model.group = str; 
				contactList.add(model); 
			} 
		} 
		adapter.refresh(contactList, false); 
    } 
	 
	/** 
	 * 根据拼音搜索 
	 * @param str			正则表达式 
	 * @param pyName		拼音 
	 * @param isIncludsive	搜索条件是否大于6个字符 
	 * @return 
	 */ 
	public boolean contains(String str, Model model, String search){ 
		if(TextUtils.isEmpty(model.pyname)){ 
			return false; 
		} 
		model.group = ""; 
		//搜索条件大于6个字符将不按拼音首字母查询 
		if(search.length() < 6){ 
			//根据首字母进行模糊查询 
			Pattern pattern = Pattern.compile("^" + str.toUpperCase().replace("-", "[*+#a-z]*")); 
			Matcher matcher = pattern.matcher(model.pyname); 
			 
			if(matcher.find()){ 
				String tempStr = matcher.group(); 
				for(int i = 0; i < tempStr.length(); i++){ 
					if(tempStr.charAt(i) >= 'A' && tempStr.charAt(i) <= 'Z'){ 
						model.group += tempStr.charAt(i); 
					} 
				} 
				return true; 
			} 
		} 
		 
		//根据全拼查询 
		Pattern pattern = Pattern.compile(str.replace("-", ""), Pattern.CASE_INSENSITIVE); 
		Matcher matcher = pattern.matcher(model.pyname); 
		boolean flag = matcher.find(); 
		if(flag){ 
			model.group = matcher.group(); 
		} 
		return flag; 
	} 

上面的代码是我从网上搜了很久才搜到的一个demo里面的代码,我整合到项目当中去,发现使用pinyin4j.jar类库效率实在有点低,所以我自己想了其他办法,不用第三方类库来实现。

下面是小巫的实现:

我找到一篇关于,中文字符转换为拼音的实现类,很有用
  1. package com.suntek.mobilemeeting.utils;  
  2.   
  3. public class ChineseSpelling {  
  4.   
  5.     private static int[] pyvalue = new int[] { -20319, -20317, -20304, -20295,  
  6.             -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036,  
  7.             -20032, -20026, -20002, -19990, -19986, -19982, -19976, -19805,  
  8.             -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741,  
  9.             -19739, -19728, -19725, -19715, -19540, -19531, -19525, -19515,  
  10.             -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275,  
  11.             -19270, -19263, -19261, -19249, -19243, -19242, -19238, -19235,  
  12.             -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006,  
  13.             -19003, -18996, -18977, -18961, -18952, -18783, -18774, -18773,  
  14.             -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697,  
  15.             -18696, -18526, -18518, -18501, -18490, -18478, -18463, -18448,  
  16.             -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201,  
  17.             -18184, -18183, -18181, -18012, -17997, -17988, -17970, -17964,  
  18.             -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752,  
  19.             -17733, -17730, -17721, -17703, -17701, -17697, -17692, -17683,  
  20.             -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427,  
  21.             -17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733,  
  22.             -16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470,  
  23.             -16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423,  
  24.             -16419, -16412, -16407, -16403, -16401, -16393, -16220, -16216,  
  25.             -16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158,  
  26.             -16155, -15959, -15958, -15944, -15933, -15920, -15915, -15903,  
  27.             -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659,  
  28.             -15652, -15640, -15631, -15625, -15454, -15448, -15436, -15435,  
  29.             -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369,  
  30.             -15363, -15362, -15183, -15180, -15165, -15158, -15153, -15150,  
  31.             -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121,  
  32.             -15119, -15117, -15110, -15109, -14941, -14937, -14933, -14930,  
  33.             -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902,  
  34.             -14894, -14889, -14882, -14873, -14871, -14857, -14678, -14674,  
  35.             -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429,  
  36.             -14407, -14399, -14384, -14379, -14368, -14355, -14353, -14345,  
  37.             -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135,  
  38.             -14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094,  
  39.             -14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907,  
  40.             -13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847,  
  41.             -13831, -13658, -13611, -13601, -13406, -13404, -13400, -13398,  
  42.             -13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343,  
  43.             -13340, -13329, -13326, -13318, -13147, -13138, -13120, -13107,  
  44.             -13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888,  
  45.             -12875, -12871, -12860, -12858, -12852, -12849, -12838, -12831,  
  46.             -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556,  
  47.             -12359, -12346, -12320, -12300, -12120, -12099, -12089, -12074,  
  48.             -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798,  
  49.             -11781, -11604, -11589, -11536, -11358, -11340, -11339, -11324,  
  50.             -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041,  
  51.             -11038, -11024, -11020, -11019, -11018, -11014, -10838, -10832,  
  52.             -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533,  
  53.             -10519, -10331, -10329, -10328, -10322, -10315, -10309, -10307,  
  54.             -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254 };  
  55.   
  56.     private static String[] pystr = new String[] { "a""ai""an""ang",  
  57.             "ao""ba""bai""ban""bang""bao""bei""ben""beng",  
  58.             "bi""bian""biao""bie""bin""bing""bo""bu""ca",  
  59.             "cai""can""cang""cao""ce""ceng""cha""chai""chan",  
  60.             "chang""chao""che""chen""cheng""chi""chong""chou",  
  61.             "chu""chuai""chuan""chuang""chui""chun""chuo""ci",  
  62.             "cong""cou""cu""cuan""cui""cun""cuo""da""dai",  
  63.             "dan""dang""dao""de""deng""di""dian""diao""die",  
  64.             "ding""diu""dong""dou""du""duan""dui""dun""duo",  
  65.             "e""en""er""fa""fan""fang""fei""fen""feng""fo",  
  66.             "fou""fu""ga""gai""gan""gang""gao""ge""gei""gen",  
  67.             "geng""gong""gou""gu""gua""guai""guan""guang""gui",  
  68.             "gun""guo""ha""hai""han""hang""hao""he""hei",  
  69.             "hen""heng""hong""hou""hu""hua""huai""huan""huang",  
  70.             "hui""hun""huo""ji""jia""jian""jiang""jiao""jie",  
  71.             "jin""jing""jiong""jiu""ju""juan""jue""jun""ka",  
  72.             "kai""kan""kang""kao""ke""ken""keng""kong""kou",  
  73.             "ku""kua""kuai""kuan""kuang""kui""kun""kuo""la",  
  74.             "lai""lan""lang""lao""le""lei""leng""li""lia",  
  75.             "lian""liang""liao""lie""lin""ling""liu""long",  
  76.             "lou""lu""lv""luan""lue""lun""luo""ma""mai""man",  
  77.             "mang""mao""me""mei""men""meng""mi""mian""miao",  
  78.             "mie""min""ming""miu""mo""mou""mu""na""nai""nan",  
  79.             "nang""nao""ne""nei""nen""neng""ni""nian""niang",  
  80.             "niao""nie""nin""ning""niu""nong""nu""nv""nuan",  
  81.             "nue""nuo""o""ou""pa""pai""pan""pang""pao""pei",  
  82.             "pen""peng""pi""pian""piao""pie""pin""ping""po",  
  83.             "pu""qi""qia""qian""qiang""qiao""qie""qin""qing",  
  84.             "qiong""qiu""qu""quan""que""qun""ran""rang""rao",  
  85.             "re""ren""reng""ri""rong""rou""ru""ruan""rui",  
  86.             "run""ruo""sa""sai""san""sang""sao""se""sen",  
  87.             "seng""sha""shai""shan""shang""shao""she""shen",  
  88.             "sheng""shi""shou""shu""shua""shuai""shuan""shuang",  
  89.             "shui""shun""shuo""si""song""sou""su""suan""sui",  
  90.             "sun""suo""ta""tai""tan""tang""tao""te""teng",  
  91.             "ti""tian""tiao""tie""ting""tong""tou""tu""tuan",  
  92.             "tui""tun""tuo""wa""wai""wan""wang""wei""wen",  
  93.             "weng""wo""wu""xi""xia""xian""xiang""xiao""xie",  
  94.             "xin""xing""xiong""xiu""xu""xuan""xue""xun""ya",  
  95.             "yan""yang""yao""ye""yi""yin""ying""yo""yong",  
  96.             "you""yu""yuan""yue""yun""za""zai""zan""zang",  
  97.             "zao""ze""zei""zen""zeng""zha""zhai""zhan""zhang",  
  98.             "zhao""zhe""zhen""zheng""zhi""zhong""zhou""zhu",  
  99.             "zhua""zhuai""zhuan""zhuang""zhui""zhun""zhuo""zi",  
  100.             "zong""zou""zu""zuan""zui""zun""zuo" };  
  101.   
  102.     private StringBuilder buffer;  
  103.   
  104.     private String resource;  
  105.   
  106.     private static ChineseSpelling chineseSpelling = new ChineseSpelling();  
  107.   
  108.     public static ChineseSpelling getInstance() {  
  109.         return chineseSpelling;  
  110.     }  
  111.   
  112.     public String getResource() {  
  113.         return resource;  
  114.     }  
  115.   
  116.     public void setResource(String resource) {  
  117.         this.resource = resource;  
  118.     }  
  119.   
  120.     private int getChsAscii(String chs) {  
  121.         int asc = 0;  
  122.         try {  
  123.   
  124.             byte[] bytes = chs.getBytes("gb2312");  
  125.   
  126.             if (bytes == null || bytes.length > 2 || bytes.length <= 0) { // 错误  
  127.   
  128.                 // log  
  129.   
  130.                 throw new RuntimeException("illegal resource string");  
  131.                 // System.out.println("error");  
  132.   
  133.             }  
  134.             if (bytes.length == 1) { // 英文字符  
  135.   
  136.                 asc = bytes[0];  
  137.             }  
  138.             if (bytes.length == 2) { // 中文字符  
  139.   
  140.                 int hightByte = 256 + bytes[0];  
  141.                 int lowByte = 256 + bytes[1];  
  142.                 asc = (256 * hightByte + lowByte) - 256 * 256;  
  143.             }  
  144.         } catch (Exception e) {  
  145.             System.out  
  146.                     .println("ERROR:ChineseSpelling.class-getChsAscii(String chs)"  
  147.                             + e);  
  148.             // e.printStackTrace();  
  149.   
  150.         }  
  151.         return asc;  
  152.     }  
  153.   
  154.     public String convert(String str) {  
  155.         String result = null;  
  156.         int ascii = getChsAscii(str);  
  157.         // System.out.println(ascii);  
  158.   
  159.         if (ascii > 0 && ascii < 160) {  
  160.             result = String.valueOf((char) ascii);  
  161.         } else {  
  162.             for (int i = (pyvalue.length - 1); i >= 0; i--) {  
  163.                 if (pyvalue[i] <= ascii) {  
  164.                     result = pystr[i];  
  165.                     break;  
  166.                 }  
  167.             }  
  168.         }  
  169.         return result;  
  170.     }  
  171.   
  172.     public String getSelling(String chs) {  
  173.         String key, value;  
  174.         buffer = new StringBuilder();  
  175.         for (int i = 0; i < chs.length(); i++) {  
  176.             key = chs.substring(i, i + 1);  
  177.             if (key.getBytes().length >= 2) {  
  178.                 value = (String) convert(key);  
  179.                 if (value == null) {  
  180.                     value = "unknown";  
  181.                 }  
  182.             } else {  
  183.                 value = key;  
  184.             }  
  185.   
  186.             buffer.append(value);  
  187.         }  
  188.         return buffer.toString();  
  189.     }  
  190.   
  191.     public String getSpelling() {  
  192.         return this.getSelling(this.getResource());  
  193.     }  
  194. }  
package com.suntek.mobilemeeting.utils; 
 
public class ChineseSpelling { 
 
	private static int[] pyvalue = new int[] { -20319, -20317, -20304, -20295, 
			-20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, 
			-20032, -20026, -20002, -19990, -19986, -19982, -19976, -19805, 
			-19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, 
			-19739, -19728, -19725, -19715, -19540, -19531, -19525, -19515, 
			-19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, 
			-19270, -19263, -19261, -19249, -19243, -19242, -19238, -19235, 
			-19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006, 
			-19003, -18996, -18977, -18961, -18952, -18783, -18774, -18773, 
			-18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, 
			-18696, -18526, -18518, -18501, -18490, -18478, -18463, -18448, 
			-18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, 
			-18184, -18183, -18181, -18012, -17997, -17988, -17970, -17964, 
			-17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, 
			-17733, -17730, -17721, -17703, -17701, -17697, -17692, -17683, 
			-17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, 
			-17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733, 
			-16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, 
			-16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423, 
			-16419, -16412, -16407, -16403, -16401, -16393, -16220, -16216, 
			-16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158, 
			-16155, -15959, -15958, -15944, -15933, -15920, -15915, -15903, 
			-15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, 
			-15652, -15640, -15631, -15625, -15454, -15448, -15436, -15435, 
			-15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369, 
			-15363, -15362, -15183, -15180, -15165, -15158, -15153, -15150, 
			-15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, 
			-15119, -15117, -15110, -15109, -14941, -14937, -14933, -14930, 
			-14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, 
			-14894, -14889, -14882, -14873, -14871, -14857, -14678, -14674, 
			-14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, 
			-14407, -14399, -14384, -14379, -14368, -14355, -14353, -14345, 
			-14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, 
			-14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094, 
			-14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, 
			-13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847, 
			-13831, -13658, -13611, -13601, -13406, -13404, -13400, -13398, 
			-13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343, 
			-13340, -13329, -13326, -13318, -13147, -13138, -13120, -13107, 
			-13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888, 
			-12875, -12871, -12860, -12858, -12852, -12849, -12838, -12831, 
			-12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, 
			-12359, -12346, -12320, -12300, -12120, -12099, -12089, -12074, 
			-12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, 
			-11781, -11604, -11589, -11536, -11358, -11340, -11339, -11324, 
			-11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, 
			-11038, -11024, -11020, -11019, -11018, -11014, -10838, -10832, 
			-10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, 
			-10519, -10331, -10329, -10328, -10322, -10315, -10309, -10307, 
			-10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254 }; 
 
	private static String[] pystr = new String[] { "a", "ai", "an", "ang", 
			"ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", 
			"bi", "bian", "biao", "bie", "bin", "bing", "bo", "bu", "ca", 
			"cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan", 
			"chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", 
			"chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", 
			"cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", 
			"dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die", 
			"ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", 
			"e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", 
			"fou", "fu", "ga", "gai", "gan", "gang", "gao", "ge", "gei", "gen", 
			"geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", 
			"gun", "guo", "ha", "hai", "han", "hang", "hao", "he", "hei", 
			"hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", 
			"hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", 
			"jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", 
			"kai", "kan", "kang", "kao", "ke", "ken", "keng", "kong", "kou", 
			"ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", 
			"lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", 
			"lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", 
			"lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai", "man", 
			"mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", 
			"mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai", "nan", 
			"nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", 
			"niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan", 
			"nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", 
			"pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", 
			"pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", 
			"qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", 
			"re", "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", 
			"run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", 
			"seng", "sha", "shai", "shan", "shang", "shao", "she", "shen", 
			"sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", 
			"shui", "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", 
			"sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng", 
			"ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", 
			"tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", 
			"weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", 
			"xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya", 
			"yan", "yang", "yao", "ye", "yi", "yin", "ying", "yo", "yong", 
			"you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", 
			"zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", 
			"zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", 
			"zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", 
			"zong", "zou", "zu", "zuan", "zui", "zun", "zuo" }; 
 
	private StringBuilder buffer; 
 
	private String resource; 
 
	private static ChineseSpelling chineseSpelling = new ChineseSpelling(); 
 
	public static ChineseSpelling getInstance() { 
		return chineseSpelling; 
	} 
 
	public String getResource() { 
		return resource; 
	} 
 
	public void setResource(String resource) { 
		this.resource = resource; 
	} 
 
	private int getChsAscii(String chs) { 
		int asc = 0; 
		try { 
 
			byte[] bytes = chs.getBytes("gb2312"); 
 
			if (bytes == null || bytes.length > 2 || bytes.length <= 0) { // 错误 
 
				// log 
 
				throw new RuntimeException("illegal resource string"); 
				// System.out.println("error"); 
 
			} 
			if (bytes.length == 1) { // 英文字符 
 
				asc = bytes[0]; 
			} 
			if (bytes.length == 2) { // 中文字符 
 
				int hightByte = 256 + bytes[0]; 
				int lowByte = 256 + bytes[1]; 
				asc = (256 * hightByte + lowByte) - 256 * 256; 
			} 
		} catch (Exception e) { 
			System.out 
					.println("ERROR:ChineseSpelling.class-getChsAscii(String chs)" 
							+ e); 
			// e.printStackTrace(); 
 
		} 
		return asc; 
	} 
 
	public String convert(String str) { 
		String result = null; 
		int ascii = getChsAscii(str); 
		// System.out.println(ascii); 
 
		if (ascii > 0 && ascii < 160) { 
			result = String.valueOf((char) ascii); 
		} else { 
			for (int i = (pyvalue.length - 1); i >= 0; i--) { 
				if (pyvalue[i] <= ascii) { 
					result = pystr[i]; 
					break; 
				} 
			} 
		} 
		return result; 
	} 
 
	public String getSelling(String chs) { 
		String key, value; 
		buffer = new StringBuilder(); 
		for (int i = 0; i < chs.length(); i++) { 
			key = chs.substring(i, i + 1); 
			if (key.getBytes().length >= 2) { 
				value = (String) convert(key); 
				if (value == null) { 
					value = "unknown"; 
				} 
			} else { 
				value = key; 
			} 
 
			buffer.append(value); 
		} 
		return buffer.toString(); 
	} 
 
	public String getSpelling() { 
		return this.getSelling(this.getResource()); 
	} 
}

不过我也发现了一问题,关于一个中文字符的字节数的问题,不同的编码可能会存在中文的字节数不同的情况,比如GBK编码的中文是2,而UTF-8的编码是3。其实我发现这个问题也挺惊奇的,这个问题可能是我们以后编码的时候会遇到的,一个编码就可能把你搞死。

英文字母:

字节数 : 1;编码:GB2312

字节数 : 1;编码:GBK

字节数 : 1;编码:GB18030

字节数 : 1;编码:ISO-8859-1

字节数 : 1;编码:UTF-8

字节数 : 4;编码:UTF-16

字节数 : 2;编码:UTF-16BE

字节数 : 2;编码:UTF-16LE

 

中文汉字:

字节数 : 2;编码:GB2312

字节数 : 2;编码:GBK

字节数 : 2;编码:GB18030

字节数 : 1;编码:ISO-8859-1

字节数 : 3;编码:UTF-8

字节数 : 4;编码:UTF-16

字节数 : 2;编码:UTF-16BE

字节数 : 2;编码:UTF-16LE

  1. /** 
  2.  * 按号码-拼音搜索联系人 
  3.  *  
  4.  * @param str 
  5.  */  
  6. public static ArrayList<Contact> search(String str,  
  7.         ArrayList<Contact> allContacts, ArrayList<Contact> contactList) {  
  8.     contactList.clear();  
  9.     // 如果搜索条件以0 1 +开头则按号码搜索  
  10.     if (str.startsWith("0") || str.startsWith("1") || str.startsWith("+")) {  
  11.         for (Contact contact : allContacts) {  
  12.             if (contact.getNumber() != null && contact.getName() != null) {  
  13.                 if (contact.getNumber().contains(str)  
  14.                         || contact.getName().contains(str)) {  
  15.                     contact.setGroup(str);  
  16.                     contactList.add(contact);  
  17.                 }  
  18.             }  
  19.         }  
  20.         return contactList;  
  21.     }  
  22.     ChineseSpelling finder = ChineseSpelling.getInstance();  
  23.   
  24.     String result = "";  
  25.     for (Contact contact : allContacts) {  
  26.         // 先将输入的字符串转换为拼音  
  27.         finder.setResource(str);  
  28.         result = finder.getSpelling();  
  29.         if (contains(contact, result)) {  
  30.             contactList.add(contact);  
  31.         } else if (contact.getNumber().contains(str)) {  
  32.             contact.setGroup(str);  
  33.             contactList.add(contact);  
  34.         }  
  35.     }  
  36.     return contactList;  
  37. }  
  38.   
  39. /** 
  40.  * 根据拼音搜索 
  41.  *  
  42.  * @param str 
  43.  *            正则表达式 
  44.  * @param pyName 
  45.  *            拼音 
  46.  * @param isIncludsive 
  47.  *            搜索条件是否大于6个字符 
  48.  * @return 
  49.  */  
  50. public static boolean contains(Contact contact, String search) {  
  51.     if (TextUtils.isEmpty(contact.getName())) {  
  52.         return false;  
  53.     }  
  54.   
  55.     boolean flag = false;  
  56.   
  57.     // 简拼匹配,如果输入在字符串长度大于6就不按首字母匹配了  
  58.     if (search.length() < 6) {  
  59.         String firstLetters = FirstLetterUtil.getFirstLetter(contact  
  60.                 .getName());  
  61.         // 不区分大小写  
  62.         Pattern firstLetterMatcher = Pattern.compile(search,  
  63.                 Pattern.CASE_INSENSITIVE);  
  64.         flag = firstLetterMatcher.matcher(firstLetters).find();  
  65.     }  
  66.   
  67.     if (!flag) { // 如果简拼已经找到了,就不使用全拼了  
  68.         // 全拼匹配  
  69.         ChineseSpelling finder = ChineseSpelling.getInstance();  
  70.         finder.setResource(contact.getName());  
  71.         // 不区分大小写  
  72.         Pattern pattern2 = Pattern  
  73.                 .compile(search, Pattern.CASE_INSENSITIVE);  
  74.         Matcher matcher2 = pattern2.matcher(finder.getSpelling());  
  75.         flag = matcher2.find();  
  76.     }  
  77.   
  78.     return flag;  
  79. }  
	/** 
	 * 按号码-拼音搜索联系人 
	 *  
	 * @param str 
	 */ 
	public static ArrayList<Contact> search(String str, 
			ArrayList<Contact> allContacts, ArrayList<Contact> contactList) { 
		contactList.clear(); 
		// 如果搜索条件以0 1 +开头则按号码搜索 
		if (str.startsWith("0") || str.startsWith("1") || str.startsWith("+")) { 
			for (Contact contact : allContacts) { 
				if (contact.getNumber() != null && contact.getName() != null) { 
					if (contact.getNumber().contains(str) 
							|| contact.getName().contains(str)) { 
						contact.setGroup(str); 
						contactList.add(contact); 
					} 
				} 
			} 
			return contactList; 
		} 
		ChineseSpelling finder = ChineseSpelling.getInstance(); 
 
		String result = ""; 
		for (Contact contact : allContacts) { 
			// 先将输入的字符串转换为拼音 
			finder.setResource(str); 
			result = finder.getSpelling(); 
			if (contains(contact, result)) { 
				contactList.add(contact); 
			} else if (contact.getNumber().contains(str)) { 
				contact.setGroup(str); 
				contactList.add(contact); 
			} 
		} 
		return contactList; 
	} 
 
	/** 
	 * 根据拼音搜索 
	 *  
	 * @param str 
	 *            正则表达式 
	 * @param pyName 
	 *            拼音 
	 * @param isIncludsive 
	 *            搜索条件是否大于6个字符 
	 * @return 
	 */ 
	public static boolean contains(Contact contact, String search) { 
		if (TextUtils.isEmpty(contact.getName())) { 
			return false; 
		} 
 
		boolean flag = false; 
 
		// 简拼匹配,如果输入在字符串长度大于6就不按首字母匹配了 
		if (search.length() < 6) { 
			String firstLetters = FirstLetterUtil.getFirstLetter(contact 
					.getName()); 
			// 不区分大小写 
			Pattern firstLetterMatcher = Pattern.compile(search, 
					Pattern.CASE_INSENSITIVE); 
			flag = firstLetterMatcher.matcher(firstLetters).find(); 
		} 
 
		if (!flag) { // 如果简拼已经找到了,就不使用全拼了 
			// 全拼匹配 
			ChineseSpelling finder = ChineseSpelling.getInstance(); 
			finder.setResource(contact.getName()); 
			// 不区分大小写 
			Pattern pattern2 = Pattern 
					.compile(search, Pattern.CASE_INSENSITIVE); 
			Matcher matcher2 = pattern2.matcher(finder.getSpelling()); 
			flag = matcher2.find(); 
		} 
 
		return flag; 
	} 


我发现自己换了这种方法之后,速度一下子提升了很多,满足了自己的需求,用第三方类库虽好,但涉及到用户体验这一块,你不得不低头,小巫总结在此,这篇博客我相信总会有人需要的,如果有帮助到你,不要忘记好评哈,你的支持将是我无限的动力。


声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号