一个电话本中联系人名字搜索高亮的实现
需求:实现电话本名字搜索功能的高亮实现,其中搜索支持中文、简拼、全拼搜索,对搜索匹配到的名字部分高亮显示。
例如:
名字:张向东
全拼: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; } } }
-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com
本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com