Android 拼音搜索中文,包含多音字

我的上一篇文章实现了拼音搜索中文的功能,但是还存在缺陷,就是无法实现多音字搜索,比如王重阳(wangchongyang,wangzhongyang)只匹配了一个。

这篇文章说说如何实现多音字的搜索,进入正题:

  1. 功能分析
    之前的映射关系是1对1,那现在的关系就是n对1。如表1所示
     

    表1
    wangchongyang王重阳
    wangzhongyang王重阳







    所以我们应该找出每个中文字的拼音,然后再排列组合,比如王重阳就有2*2*1=4种组合,因为王也是多音字,wang2,wang4,如表2所示
     
    表2
    wang2chongyang
    wang2zhongyang
    wang4chongyang
    wang4zhongyang











    因为我们拼音搜索不需要声调,所以最终王重阳就注意两种拼音,wangchongyang,wangzhongyang,所以我们先找出四种拼音,然后再去重。
    思路大概就是这样子,下面说说实现过程
     

  2. 功能实现
    方法 PinyinHelper.toHanyuPinyinStringArray(c, format),可以获取某个字的多拼音数组,所以先获取某个人名的每个字拼音的数组集合,代码如下:
     

        for (final String s : list) {
                List<String[]> pinYinManagerBeans = new ArrayList<>();
                for (int i = 0; i < s.length(); i++) {
                    char c = s.charAt(i);
                    String[] cStrHY = new String[0];
                    try {
                        cStrHY = PinyinHelper.toHanyuPinyinStringArray(c, format);
                    } catch (BadHanyuPinyinOutputFormatCombination     
                badHanyuPinyinOutputFormatCombination) {
                        badHanyuPinyinOutputFormatCombination.printStackTrace();
                    }
                    pinYinManagerBeans.add(cStrHY);
                }
        
          ..................
          ..................
    
         }

    获取每个字的多拼音,保存到pinYinManagerBeans 
    接下来就是如何获取他们的排列组合
    pinYinManagerBeans.get(0)和pinYinManagerBeans.get(1),先组合,形成新的集合List,List再跟pinYinManagerBeans.get(2)组合,形成新集合。。。。以此类推
    所以先获取第一个字的多拼音组合,赋值给List,代码如下

     List<String> strings = new ArrayList<>();
     strings.addAll(Arrays.asList(pinYinManagerBeans.get(0)));

    然后再循环获取并赋值给List,最后再去重就可以了。这样我们就获取了所有的拼音组合了
     

     /**
         * 获取中文拼音 (包含多音字)
         * @param strings 中文数据集
         * @param pinYins 多拼音集合
         * @param index 下标
         */
        public static void getPinYinKey(List<String> strings, List<String[]> pinYins, int index,PinYinCallBack pinYinCallBack) {
    
            List<String> stringList = new ArrayList<>();
            for (String s : strings) {
                for (String s2 : pinYins.get(index)) {
                    StringBuffer stringBuffer = new StringBuffer();
                    stringBuffer.append(s);
                    stringBuffer.append(s2);
                    stringList.add(stringBuffer.toString());
                }
            }
            if (pinYins.size() > index + 1) {
                getPinYinKey(stringList, pinYins, index + 1,pinYinCallBack);
            } else {
                removal(stringList);
                pinYinCallBack.callBack(stringList);
            }
        }
    
        /**
         * 去重
         * @param stringList 数据源
         */
        public static void removal(List<String> stringList){
            HashSet<String> hashSet = new HashSet<>(stringList);
            stringList.clear();
            stringList.addAll(hashSet);
        }

    CallBack只是个回调,处理好所以拼音后,再跟中文名,一一匹配

                         @Override
                        public void callBack(List<String> pinyins) {
                            for (String pinyin : pinyins) {
                                UserName userName = new UserName();
                                userName.setPinyin(pinyin);
                                userName.setName(s);
                                userNameList.add(userName);
                            }
                        }

    这样就形成了多对一数据集合,到这里感觉已经结束,其实并没有。看一下效果就知道了


    因为多对一只是方便我们搜索,我们展现给用户的还是中文,那这样就会出现重复的中文,所以我们展示的时候还需要过滤。
    还记得这个方法吗 publishResults(CharSequence constraint, FilterResults results)  接收过滤后的结果
    所以过滤后的结果,我们还可以在这里做一个中文名字的过滤,这样展示就不会出现重复中文名了,nice,下面就是过滤中文名的代码
     

     //去重,获取新集合
        private List<UserName> getNewList(List<UserName> list){
            List<UserName> userNameList = new ArrayList<>();
            List<String> stringList = new ArrayList<>();
            for (UserName userName : list) {
                if (!stringList.contains(userName.getName())){
                    stringList.add(userName.getName());
                    userNameList.add(userName);
                }
            }
            return userNameList;
        }

    看一下运行效果
                             

  3. 总结

    到此,拼音搜索中文的功能就全部完成了,这个功能的难点其实是在于过滤和多音字的处理。
    那可能有人会问了,首字母搜索还没做啊,多音字都做出来了,首字母还不会吗?
    最后,项目地址:https://github.com/tongtian00/CustonSearch

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页