快速搜索匹配联系人算法

喻嘉泽
2023-12-01

在通讯录应用中,快速搜索匹配符合关键字的联系人,是一个必备的需求。比如要搜索 名字 尼古拉斯赵四 ,电话号码 1234567 这个联系人,我们可以输入:

1.中文全名 尼古拉斯赵四
2.中文部分名字 赵四
3.拼音全拼 nigulasizhaosi
4.拼音部分 nigu
5.拼音部分首字 ngls
6.拼音首字和部分全拼 ngulasi
7.电话号码匹配

如此多的搜索方式,如果没有一个比较恰当的算法,会导致有很多的if else判断,逻辑也会显得比较复杂。下面是我总结的一个高效的算法。
对于电话号码和纯中文的匹配,应该是没什么难度的,直接检索就可以了,难点是拼音首字母和拼音全拼的组合差异。解决方法就是在联系人的数据结构中准备两个字符串集合,一个集合存储每个中文字的拼音首字母,一个集合存储每个中文字的全拼,在检索的时候对这两个集合做适当的排列组合,去匹配拼音可能的组合方式。

public class ContactItem {

    private String name;     //名字
    private char firstChar;  //索引的首字母
    private String number;   //电话号码
    private List<String> fullpingyins = new ArrayList<>();
    private List<String> firstpingyins = new ArrayList<>();
 Pattern p = Pattern.compile("[\u4E00-\u9FA5a-zA-Z]+");
            Matcher m = p.matcher(item.getName());
            if(m.lookingAt()){
                //如果是以汉字或字母开头,则获取拼音字符串和首字符
                int end = m.end();
                String substr = item.getName().substring(0,end);
                char [] namechars = substr.toCharArray();

                //获取全拼
                for(char c : namechars){
                    String pingyin = getPingyin(c);
                    item.getFullpingyins().add(pingyin);
                }

                //每个字的首字母
                 char [] firstpingyins = getFirstSpell(substr).toCharArray();
                 for (char c : firstpingyins){
                     item.getFirstpingyins().add(String.valueOf(c));
                 }

                item.setFirstChar(firstpingyins[0]);
            }

把数据准备好之后,接下来就是匹配搜索

 public void search(final String keystr, final boolean onlyNumber){
        Thread thread = new Thread(){
            @Override
            public void run() {
                List<ContactItem> matchlist = new ArrayList<>();

                for (ContactItem item : contactItems){

                    Pattern pattern = Pattern.compile(keystr);
                    Matcher matcher = null;

                    //匹配全名
                    StringBuffer stringBuffer = new StringBuffer();
                    matcher = pattern.matcher(stringBuffer.append(item.getFullpingyins()));
                    if(matcher.find()){
                        matchlist.add(item);
                        continue;
                    }
                     //匹配缩写
                    stringBuffer = new StringBuffer();
                    matcher = pattern.matcher(stringBuffer.append(item.getFirstpingyins()));
                    if(matcher.lookingAt()){
                        matchlist.add(item);
                        continue;
                    }
                    if(matcher.find()){
                        matchlist.add(item);
                        continue;
                    }
                    boolean isfind = false;

                    //缩写加全写,先把缩写逐个替换到全称中匹配
                    for(int f = 0 ; f < item.getFirstpingyins().size() ; f++){
                        StringBuffer sb = new StringBuffer();
                        for (int k =0 ; k < item.getFullpingyins().size() ;k ++){
                            if(f == k){
                                sb.append(item.getFirstpingyins().get(f));
                                continue;
                            }
                            sb.append(item.getFullpingyins().get(k));
                        }

                        matcher = pattern.matcher(sb);
                        if(matcher.lookingAt()){
                            matchlist.add(item);
                            isfind = true;
                            break;
                        }
                    }

                    if(isfind){
                        continue;
                    }
                     //缩写加全写,把全拼逐个替换到缩写中匹配
                    for(int f = 0 ; f < item.getFullpingyins().size() ; f++){
                        StringBuffer sb = new StringBuffer();
                        for (int k =0 ; k < item.getFirstpingyins().size() ;k ++){
                            if(f == k){
                                sb.append(item.getFullpingyins().get(f));
                                continue;
                            }
                            sb.append(item.getFirstpingyins().get(k));
                        }

                        matcher = pattern.matcher(sb);
                        if(matcher.lookingAt()){
                            matchlist.add(item);
                            isfind = true;
                            break;
                        }
                    }
                    if(isfind){
                        continue;
                    }

                    //匹配号码
                    if(TextUtils.isEmpty(item.getNumber())){
                        continue;
                    }
                    matcher = pattern.matcher(item.getNumber());
                    if(matcher.find()){
                        matchlist.add(item);
                        continue;
                    }

                }
            }
        };

        thread.start();
    }
 类似资料: