標籤:撥號軟體 android 快速撥號 演算法 連絡人
接上篇,下面是幾個匹配演算法的詳情:
1.完全符合
完全符合很簡單了,只要判斷string是否相等就行了。這裡要判斷所有拼音和所有號碼。如果拼音已經符合,就不再判斷號碼。反正是一個人……
private ScoreAndHits completeMatch(String reg) {ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,new ArrayList<PointPair>());for (int i = 0; i < fullNameNumberWithoutSpace.size(); i++) {String str = fullNameNumberWithoutSpace.get(i);if (reg.equals(str)) {scoreAndHits.nameIndex = i;scoreAndHits.score = Match_Level_Complete;scoreAndHits.pairs.add(new PointPair(i, -1));scoreAndHits.matchLevel = Level_Complete;return scoreAndHits;}}for (int i = 0; i < phones.size(); i++) {PhoneStruct phone = phones.get(i);if (reg.equals(phone.phoneNumber)) {scoreAndHits.nameIndex = i;scoreAndHits.score = Match_Level_Complete;scoreAndHits.pairs.add(new PointPair(i, -1));scoreAndHits.matchType = Match_Type_Phone;scoreAndHits.matchLevel = Level_Complete;return scoreAndHits;}}// 走到這裡說明沒有匹配return new ScoreAndHits(-1, 0f, new ArrayList<PointPair>());}
2.前置首字母溢出匹配。(能不能想個好聽的名字650) this.width=650;" src="http://img.baidu.com/hi/jx2/j_0004.gif" alt="j_0004.gif" />)
private ScoreAndHits foreAcronymOverFlowMatch(String reg) { // 因為有可能是多音字,所以這個方法用來對比不同拼音的匹配度,並取最大的那個ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,new ArrayList<PointPair>());for (int i = 0; i < fullNameNumber.size(); i++) {ArrayList<String> names = fullNameNumber.get(i);ScoreAndHits tmpscore = foreAcronymOverFlowMatch(names, reg);if (tmpscore.score > scoreAndHits.score) {scoreAndHits = tmpscore;scoreAndHits.nameIndex = i;}}scoreAndHits.matchLevel = Level_Fore_Acronym_Overflow;return scoreAndHits;}// 在第一個字母確定的情況下,第二個字母有可能有三種情況// 一、在第一個字母所在單詞的鄰居位置charAt(x+1);// 二、在第二個單詞的首字母處// 三、以上兩種情況皆不符合,不匹配,出局private ScoreAndHits foreAcronymOverFlowMatch(ArrayList<String> names,String reg) {// 用來得出某一個拼音的匹配值。ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,new ArrayList<PointPair>());if (names.get(0).charAt(0) == reg.charAt(0)) { //其實crossWords()方法才是求匹配值的方法,lolOverflowMatchValue value = crossWords(names, reg, 0, 0, 0);int cross = crossWords(names, reg, 0, 0, 0).crossed;if (cross > 0) {scoreAndHits.score = Match_Level_Fore_Acronym_Overflow + cross* Match_Score_Reward - (names.size() - cross)* Match_Miss_Punish;scoreAndHits.pairs = value.pairs;}}return scoreAndHits;}/** * 返回一串字元能跨越另一串字元的長度,根據上面的匹配規則,要儘可能的多匹配單詞。若要保證 * 能匹配最長的長度,只要保證下一個字元開始的一段字元能匹配 * 最長的長度即可,換名話說,如果想要讓96758匹配最長的字串,那麼只要保證6758能匹配最長 * 的字串即可,然後758,再然後58……。例如,名字叫PanAnNing,輸入pan,那麼應該匹配三個 * 首字母,PAN,而不是第一姓的拼音Pan. * 這是一個遞迴。 * * @param names * @param regString * 匹配字串 * @param listIndex * 匹配到的list的第listIndex個單詞 * @param strIndex * 匹配到第listIndex個單詞中的第strIndex個字母 * @param regIndex * regchar的匹配位置,比如匹配到了96758的7上,也就是regIndex==2. * @return */private OverflowMatchValue crossWords(ArrayList<String> names,String regString, int listIndex, int strIndex, int regIndex) {OverflowMatchValue result = new OverflowMatchValue(0, false);OverflowMatchValue reser = new OverflowMatchValue(0, false);OverflowMatchValue impul = new OverflowMatchValue(0, false);if (regIndex < regString.length() - 1) {char nextChar = regString.charAt(regIndex + 1);if (listIndex < names.size() - 1&& nextChar == names.get(listIndex + 1).charAt(0)) {impul = crossWords(names, regString, listIndex + 1, 0,regIndex + 1);}if (strIndex < names.get(listIndex).length() - 1&& nextChar == names.get(listIndex).charAt(strIndex + 1)) {reser = crossWords(names, regString, listIndex, strIndex + 1,regIndex + 1);}} else {result = new OverflowMatchValue((strIndex == 0) ? 1 : 0, true);result.pairs.add(0, new PointPair(listIndex, strIndex));}if (reser.matched || impul.matched) {if (impul.crossed > reser.crossed) {result = impul;} else {result = reser;}result.matched = true;result.crossed = ((strIndex == 0) ? 1 : 0)+ Math.max(result.crossed, result.crossed);result.pairs.add(0, new PointPair(listIndex, strIndex));}return result;}static class OverflowMatchValue {public int crossed = 0;public boolean matched = false;public ArrayList<PointPair> pairs = new ArrayList<PointPair>();public OverflowMatchValue(int c, boolean m) {this.crossed = c;this.matched = m;}}
3.後置首字母溢出匹配。(能不能想個好聽的名字650) this.width=650;" src="http://img.baidu.com/hi/jx2/j_0004.gif" alt="j_0004.gif" />)
跟前置首字母溢出匹配基本一樣,只不過匹配的第一個字母不再是姓的首字母。
private ScoreAndHits backAcronymOverFlowMatch(String reg) { //跟上面差不多ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,new ArrayList<PointPair>());for (int i = 0; i < fullNameNumber.size(); i++) {ArrayList<String> names = fullNameNumber.get(i);ScoreAndHits tmp = backAcronymOverFlowMatch(names, reg);if (tmp.score > scoreAndHits.score) {scoreAndHits = tmp;scoreAndHits.nameIndex = i;}}scoreAndHits.matchLevel = Level_Back_Acronym_Overflow;return scoreAndHits;}private ScoreAndHits backAcronymOverFlowMatch(ArrayList<String> names,String reg) {int score = 0;int punish = 0;ScoreAndHits scoreAndHits = new ScoreAndHits(-1, 0f,new ArrayList<PointPair>());// 有可能會調用多次crossWords,取決於名字的長度。這是跟前面的不同for (int i = 0; i < names.size(); i++) {String string = (String) names.get(i);if (string.charAt(0) == reg.charAt(0)) {OverflowMatchValue value = crossWords(names, reg, i, 0, 0);int cross = value.crossed;int lost = names.size() - cross;if (cross > score || cross == score && punish > lost) {scoreAndHits.pairs = value.pairs;score = cross;punish = lost;}}}if (score > 0) {scoreAndHits.score = Match_Level_Back_Acronym_Overflow + score* Match_Score_Reward - punish * Match_Miss_Punish;return scoreAndHits;} else {return new ScoreAndHits(-1, 0f, new ArrayList<PointPair>());}}
4.後置無頭匹配。(難聽就難聽了,反正就那個意思)
private ScoreAndHits backHeadlessParagraphMatch(String reg) {int punish = 0;ScoreAndHits scoreAndHits = new ScoreAndHits(-1, -1f,new ArrayList<PointPair>());scoreAndHits.matchLevel = Level_Headless;scoreAndHits.matchType = Match_Type_Phone;// 算了不匹配姓名了,假設沒人會得這麼離譜for (int i = 0; i < phones.size(); i++) {PhoneStruct phone = phones.get(i);int sco = phone.phoneNumber.indexOf(reg);if (sco >= 0) {int lost = phone.phoneNumber.length() - reg.length();if (scoreAndHits.score < sco || sco == scoreAndHits.score&& punish > lost) {scoreAndHits.score = sco;scoreAndHits.nameIndex = i;// 儘管有可能匹配的字串很長,但是因為是連貫的,所以只要// add一個就夠啦scoreAndHits.pairs.add(new PointPair(i, sco));punish = lost;}}}if (scoreAndHits.score >= 0) {scoreAndHits.score = Match_Level_Headless - scoreAndHits.score* Match_Score_Reward - punish * Match_Miss_Punish;}return scoreAndHits;}
到這裡已經可以得出輸入字串與連絡人的匹配度了,剩下的事情就是調用和顯示了,但是這不是本文的重點650) this.width=650;" src="http://img.baidu.com/hi/jx2/j_0010.gif" alt="j_0010.gif" />
本文出自 “NashLegend” 部落格,請務必保留此出處http://nashlegend.blog.51cto.com/5635342/1566111
Android快速撥號匹配演算法(二)