一個電話本中聯絡人名字搜尋高亮的實現
阿新 • • 發佈:2018-11-04
一個電話本中聯絡人名字搜尋高亮的實現
需求:實現電話本名字搜尋功能的高亮實現,其中搜索支援中文、簡拼、全拼搜尋,對搜尋匹配到的名字部分高亮顯示。
例如:
名字:張向東
全拼: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;
}
}
}