1. 程式人生 > >一個電話本中聯絡人名字搜尋高亮的實現

一個電話本中聯絡人名字搜尋高亮的實現

一個電話本中聯絡人名字搜尋高亮的實現

需求:實現電話本名字搜尋功能的高亮實現,其中搜索支援中文、簡拼、全拼搜尋,對搜尋匹配到的名字部分高亮顯示。


例如:

名字:張向東

全拼:zhangxiangdong

簡拼:zxd

搜尋匹配優先規則:中文(直接匹配)、簡拼匹配、全拼匹配

關鍵在全拼匹配上面,比方使用者輸入gd,則匹配向東兩個字,同xiangdong的匹配項


搜尋功能通過資料庫的搜尋匹配實現,也就是輸入是搜尋的輸入字串mInputStr和搜尋的名字結果列表List<User> 

SearchHighLightUtil的建構函式

上程式碼:

第一版:PinyinUtil為使用開源的漢字轉拼音的Jar包

 
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class SearchHighLightUtil { 
	/*
	* 輸入的搜尋字串
	*/
	private String mInputStr;
	
	/*
	* 輸入的搜尋結果
	*/
	private List<User> mListResult;
	
	/*
	* 用名字作為關鍵字,得到匹配名字的起始位置和結束位置
	*/
	private Map<String, SearchKeyPosition> mAnalyzeResult;
	
	/*
	* 構造方法
	*/ 
	public SearchHighLightUtil(String inputStr, List<User> listResult){
		this.mInputStr = inputStr;
		this.mListResult = listResult;
		
		/*
		分析輸入的字串和搜尋匹配的結果,將分析的結果儲存在mAnalyzeResult中,用名字作為關鍵字,得到匹配名字的起始位置和結束位置
		*/
		this.analyze();
	}

	public  Map<String, SearchKeyPosition> getAnalyzeResult(){
		return mAnalyzeResult;
	}
	
	private void analyze(){
		if (mAnalyzeResult == null){
			mAnalyzeResult = new HashMap<String, SearchKeyPosition>();
		}
		if (mListResult == null || mInputStr == null){
			return;
		}
		for(int i=0; i<mListResult.size(); i++){
			String name = mListResult.get(i).getName();
			String jpName = mListResult.get(i).getJPName();
			String qpName = mListResult.get(i).getQPName(); 
			
			String []jpNameArr = jpName.split("#");
			if (jpNameArr.length > 1){
				if (jpNameArr[0].contains(mInputStr)){
					jpName = jpNameArr[0];
				}else if (jpNameArr[1].contains(mInputStr)){
					jpName = jpNameArr[1];
				}
			} 
			
			if (name.contains(mInputStr)){
				int start = name.indexOf(mInputStr);
				int end = start + mInputStr.length() - 1;
				mAnalyzeResult.put(name, new SearchKeyPosition(start, end));
			}else if (jpName.contains(mInputStr)){ 
				int start = jpName.indexOf(mInputStr);
				int end = start + mInputStr.length() - 1;
				mAnalyzeResult.put(name, new SearchKeyPosition(start, end));
			}else if (qpName.contains(mInputStr)){ 
				int start = qpName.indexOf(mInputStr);
				if (start == -1){
					continue;
				}
				int end = mInputStr.length();  
				int nameLength = jpName.length() > name.length()?name.length():jpName.length();
				switch(nameLength){
					case 2:
					{ 
						String firstPinYin = PinyinUtil.getFullSpell(name.substring(0, 1)); 
						int col = (start + mInputStr.length());
						if (start <= (firstPinYin.length() - 1)){
							if (col <= firstPinYin.length()){
								start = 0;
								end = 0;
							}else{
								start = 0;
								end = 1;
							}
						}else {
							start = 1;
							end = 1;
						}
						break;
					}
					case 3:
					{
						String firstPinYin = PinyinUtil.getFullSpell(name.substring(0, 1));
						String sencondPinYin = PinyinUtil.getFullSpell(name.substring(1,2));  
						int col = (start + mInputStr.length());
						if (start <= (firstPinYin.length() - 1)){
							if (col <= firstPinYin.length()){
								start = 0;
								end = 0;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length())){
								start = 0;
								end = 1;
							}else {
								start = 0;
								end = 2;
							}
						}else  if (start <= (firstPinYin.length() + sencondPinYin.length()- 1)){
							if (col <= (firstPinYin.length() + sencondPinYin.length())){
								start = 1;
								end = 1;
							} else {
								start = 1;
								end = 2;
							}
						}else{ 
							start = 2;
							end = 2;
						}
					}
						break;
					case 4:
					{ 
						String firstPinYin = PinyinUtil.getFullSpell(name.substring(0, 1));
						String sencondPinYin = PinyinUtil.getFullSpell(name.substring(1,2)); 
						String thirdPinYin = PinyinUtil.getFullSpell(name.substring(2,3));  
						int col = (start + mInputStr.length());
						if (start <= (firstPinYin.length() - 1)){
							if (col <= firstPinYin.length()){
								start = 0;
								end = 0;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length())){
								start = 0;
								end = 1;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length())){
								start = 0;
								end = 2;
							}else{
								start = 0;
								end = 3;
							}
						}else  if (start <= (firstPinYin.length() + sencondPinYin.length()- 1)){
							if (col <= (firstPinYin.length() + sencondPinYin.length())){
								start = 1;
								end = 1;
							} else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length())){
								start = 1;
								end = 2;
							}else{
								start = 1;
								end = 3;
							} 
						}else  if (start <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length()- 1)){
							if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length())){
								start = 2;
								end = 2;
							} else {
								start = 2;
								end = 3;
							}
						}else{ 
							start = 3;
							end = 3;
						}
					}
						break;
					case 5:
					{ 
						String firstPinYin = PinyinUtil.getFullSpell(name.substring(0, 1));
						String sencondPinYin = PinyinUtil.getFullSpell(name.substring(1,2)); 
						String thirdPinYin = PinyinUtil.getFullSpell(name.substring(2,3));  
						String fourthPinYin = PinyinUtil.getFullSpell(name.substring(3,4));  
						int col = (start + mInputStr.length());
						if (start < (firstPinYin.length() - 1)){
							if (col <= firstPinYin.length()){
								start = 0;
								end = 0;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length())){
								start = 0;
								end = 1;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length())){
								start = 0;
								end = 2;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length() + fourthPinYin.length())){
								start = 0;
								end = 3;
							}else{
								start = 0;
								end = 4;
							}
						}else  if (start < (firstPinYin.length() + sencondPinYin.length()- 1)){
							if (col <= (firstPinYin.length() + sencondPinYin.length())){
								start = 1;
								end = 1;
							} else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length())){
								start = 1;
								end = 2;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length() + fourthPinYin.length())){
								start = 1;
								end = 3;
							}else{
								start = 1;
								end = 4;
							} 
						}else  if (start < (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length()- 1)){
							if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length())){
								start = 2;
								end = 2;
							}else if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length() + fourthPinYin.length())){
								start = 2;
								end = 3;
							} else {
								start = 2;
								end = 4;
							}
						}else  if (start < (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length() + + fourthPinYin.length()- 1)){
							if (col <= (firstPinYin.length() + sencondPinYin.length() + thirdPinYin.length() + fourthPinYin.length())){
								start = 3;
								end = 3; 
							} else {
								start = 3;
								end = 4;
							}
						}else { 
							start = 4;
							end = 4;
						}
					}
						break;
					default:
						start = -1;
						end = -1;
						break;
				} 
				mAnalyzeResult.put(name, new SearchKeyPosition(start, end));
			}
		}
	}

	public static class User{
		private String name;
		private String jpName;
		private String qpName;
		
		public String getName(){
			return name;
		}
		public String getJPName(){
			return jpName;
		}
		public String getQPName(){
			return qpName;
		}
	}
	
	public static class SearchKeyPosition{
		public int start = -1;
		public int end = -1;
		public SearchKeyPosition(int start, int end){
			this.start = start;
			this.end = end;
		}
	}
}



得到搜尋的字串在名字中匹配的開始位置和結束位置後,就可以設定高亮了:

	/**
	 * 關鍵字高亮變色
	 * 
	 * @param color
	 *            變化的色值
	 * @param text
	 *            文字
	 * @param keyword
	 *            文字中的關鍵字
	 * @return
	 */
	public static SpannableString matcherSearchTitle(int color, String text,
			String keyword) {
		SpannableString s = new SpannableString(text);
		Pattern p = Pattern.compile(keyword);
		Matcher m = p.matcher(s);
		while (m.find()) {
			int start = m.start();
			int end = m.end();
			s.setSpan(new ForegroundColorSpan(color), start, end,
					Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		return s;
	}

第二版:

主要對於全拼匹配的部分做了一個優化,第一版本對有幾個漢字有約束,並且最大支援5個漢字,擴充套件性不好,第二版本改進了這個問題,用迴圈的方式實現;這樣的改進也算是對思路的一個梳理。 

 
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class SearchHighLightUtil { 
	/*
	* 輸入的搜尋字串
	*/
	private String mInputStr;
	
	/*
	* 輸入的搜尋結果
	*/
	private List<User> mListResult;
	
	/*
	* 用名字作為關鍵字,得到匹配名字的起始位置和結束位置
	*/
	private Map<String, SearchKeyPosition> mAnalyzeResult;
	
	/*
	* 構造方法
	*/ 
	public SearchHighLightUtil(String inputStr, List<User> listResult){
		this.mInputStr = inputStr;
		this.mListResult = listResult;
		
		/*
		分析輸入的字串和搜尋匹配的結果,將分析的結果儲存在mAnalyzeResult中,用名字作為關鍵字,得到匹配名字的起始位置和結束位置
		*/
		this.analyze();
	}

	public  Map<String, SearchKeyPosition> getAnalyzeResult(){
		return mAnalyzeResult;
	}
	
	private void analyze(){
		if (mAnalyzeResult == null){
			mAnalyzeResult = new HashMap<String, SearchKeyPosition>();
		}
		if (mListResult == null || mInputStr == null){
			return;
		}
		for(int i=0; i<mListResult.size(); i++){
			String name = mListResult.get(i).getName();
			String jpName = mListResult.get(i).getJPName();
			String qpName = mListResult.get(i).getQPName(); 
			
			String []jpNameArr = jpName.split("#");
			if (jpNameArr.length > 1){
				if (jpNameArr[0].contains(mInputStr)){
					jpName = jpNameArr[0];
				}else if (jpNameArr[1].contains(mInputStr)){
					jpName = jpNameArr[1];
				}
			} 
			
			if (name.contains(mInputStr)){
				int start = name.indexOf(mInputStr);
				int end = start + mInputStr.length() - 1;
				mAnalyzeResult.put(name, new SearchKeyPosition(start, end));
			}else if (jpName.contains(mInputStr)){ 
				int start = jpName.indexOf(mInputStr);
				int end = start + mInputStr.length() - 1;
				mAnalyzeResult.put(name, new SearchKeyPosition(start, end));
			}else if (qpName.contains(mInputStr)){ 
				int start = qpName.indexOf(inputStr);
				if (start == -1){
					continue;
				}
				int end = -1;
				int lastLength = 0;
				int col = (start + inputStr.length());
				for (int j = 0; j<name.length(); j++){
					String pinYin = PinyinUtil.getFullSpell(name.substring(j, j+1));
                    lastLength += pinYin.length();
					if (start <= lastLength - 1){
						start = j;
						int lastEndLength = lastLength;
                        if (col <= lastEndLength){
                            end = j;
                            mAnalyzeResult.put(name, new TapPosition(start, end));
                        }else {
                            for (int k = j + 1; k < name.length(); k++) {
                                pinYin = PinyinUtil.getFullSpell(name.substring(k, k + 1));
                                lastEndLength += pinYin.length();
                                if (col <= lastEndLength) {
                                    end = k;
                                    mAnalyzeResult.put(name, new TapPosition(start, end));
                                    break;
                                }
                            }
                        }
						break;
					}
				} 
			}
		}
	}

	public static class User{
		private String name;
		private String jpName;
		private String qpName;
		
		public String getName(){
			return name;
		}
		public String getJPName(){
			return jpName;
		}
		public String getQPName(){
			return qpName;
		}
	}
	
	public static class SearchKeyPosition{
		public int start = -1;
		public int end = -1;
		public SearchKeyPosition(int start, int end){
			this.start = start;
			this.end = end;
		}
	}
}