一个电话本中联系人名字搜索高亮的实现

一个电话本中联系人名字搜索高亮的实现


需求:实现电话本名字搜索功能的高亮实现,其中搜索支持中文、简拼、全拼搜索,对搜索匹配到的名字部分高亮显示。




例如:


名字:张向东


全拼: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;
		}
	}
}

白俊遥博客

请先登录后发表评论
  • 最新评论
  • 总共0条评论