使用Java实现拼音模糊搜索功能(支持拼音、首字母、多音字、谐音字、汉字、阿拉伯数字) 您所在的位置:网站首页 数一数的数字怎么拼音 使用Java实现拼音模糊搜索功能(支持拼音、首字母、多音字、谐音字、汉字、阿拉伯数字)

使用Java实现拼音模糊搜索功能(支持拼音、首字母、多音字、谐音字、汉字、阿拉伯数字)

2024-07-03 00:14| 来源: 网络整理| 查看: 265

🍎 介绍

Java实现的简单的工具类支持(拼音, 多音字, 谐音字, 汉字, 阿拉伯数字) 对标阿里钉钉的上方搜索栏实现的

🍉 对应依赖 com.github.open-android pinyin4j 2.5.0 // https://mvnrepository.com/artifact/com.github.open-android/pinyin4j implementation group: 'com.github.open-android', name: 'pinyin4j', version: '2.5.0' 🔥 代码调试 代码中含有一个main方法, 在方法传入参数即可使用fuzzyQuery()就是模糊查询的方法, name即为用户输入的拼音, userName即为需要匹配的名称集合

 

👀 业务思路 当库中已进行租户隔离并且业务数据较少时,您可以使用工具类对库中的姓名进行模糊匹配(前提需要将库中所有的数据查询出来进行比对),并将结果全部查出, 再将结果去库中查询当库中的数据量庞大且增长速度快时,我们建议将生成的拼音字符串存储到MySQL中,然后再进行模糊匹配操作。这样可以提高查询效率。 💰 源码

仓库地址(后期会更新) : https://gitee.com/programmer-k/pinyin-fuzzy-search

package com.itjcloud.dingdong.server.common.utils; import cn.hutool.core.collection.CollectionUtil; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import net.sourceforge.pinyin4j.PinyinHelper; import java.util.*; import java.util.stream.Collectors; /** * 拼音模糊搜索工具类 */ @Slf4j public class PinyinFuzzySearchUtil { //汉字 private static final int CHINESE_CHARACTER = 1; //拼音 private static final int PIN_YIN = 2; //即包含汉字,也包含字母 private static final int WHOLE = 3; //测试方法 public static void main(String[] args) { System.out.println("------------------------------最终搜索结果>>>" + fuzzyQuery("zhang", Arrays.asList("刘长青1号?测试", "刘长青2号[]+-", "忘长长", "张长"))); } // 将n个数组元素进行组合 public static List combineArrays(List arrays) { List result = new ArrayList(); // 从索引0开始组合 combineHelper(arrays, 0, "", result); return result; } // 递归函数,用于将数组元素进行组合 private static void combineHelper(List arrays, int index, String current, List result) { // 当索引等于数组个数时,表示已经遍历完所有数组元素,将当前组合添加到结果列表中 if (index == arrays.size()) { result.add(current); return; } // 获取当前数组 List currentArray = arrays.get(index); // 遍历当前数组的元素 for (String word : currentArray) { // 递归调用,将当前元素与下一个数组进行组合 combineHelper(arrays, index + 1, current + word, result); } } /** * 拼音转换(不含首字母) * * @param chinese 中文姓名 * @return 拼音 */ public static List pinYinConvertNoInitial(String chinese) { // 存储拼音字符串 List pinyinArrays = new ArrayList(); for (int i = 0; i < chinese.length(); i++) { char c = chinese.charAt(i); // 忽略空格 if (Character.isWhitespace(c)) { continue; } String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c); log.info("pinyinArray:{}", (Object) pinyinArray); if (pinyinArray != null && pinyinArray.length > 0) { // 使用正则表达式去除声调 List pinyin = Arrays.stream(pinyinArray).map(str -> str.replaceAll("[1-5]", "")).collect(Collectors.toList()); pinyinArrays.add(pinyin); } } //最终的拼音组合 System.out.println("---------" + pinyinArrays); List pinyinCombinations = combineArrays(pinyinArrays); log.info("输出拼音:{}", JSON.toJSONString(pinyinCombinations)); return pinyinCombinations; } /** * 拼音转换 * * @param chinese 中文姓名 * @return 拼音和首字母 */ public static String pinYinConvert(String chinese) { // 存储拼音字符串 List pinyinArrays = new ArrayList(); // 存储首字母 List initialArrays = new ArrayList(); for (int i = 0; i < chinese.length(); i++) { char c = chinese.charAt(i); // 忽略空格 if (Character.isWhitespace(c)) { continue; } String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c); log.info("pinyinArray:{}", (Object) pinyinArray); if (pinyinArray != null && pinyinArray.length > 0) { // 使用正则表达式去除声调 List pinyin = Arrays.stream(pinyinArray).map(str -> str.replaceAll("[1-5]", "")).collect(Collectors.toList()); pinyinArrays.add(pinyin); //首字母 List initial = Arrays.stream(pinyinArray).map(str -> str.replaceAll("[1-5]", "")).map(str -> String.valueOf(str.charAt(0))).collect(Collectors.toList()); initialArrays.add(initial); } } //最终的拼音组合 List pinyinCombinations = combineArrays(pinyinArrays); String pinyinCombinationsJoin = String.join(",", pinyinCombinations); //最终的首字母组合 List initialCombinations = combineArrays(initialArrays); String initialCombinationsJoin = String.join(",", initialCombinations); log.info("输出首字母,拼音:{}", initialCombinationsJoin + "," + pinyinCombinationsJoin); return initialCombinationsJoin + "," + pinyinCombinationsJoin; } /** * 汉字模糊搜索 * * @param chineseCharacters 用户输入的汉字 * @param userName 需要匹配的名称集合 * @return 匹配成功用户名称 */ public static List chineseCharactersFuzzySearch(String chineseCharacters, List userName) { if (CollectionUtil.isEmpty(userName)) { log.info("userName为空"); return null; } //如果用户输入的是单个字符,则按照中文模糊搜索 if (chineseCharacters.length() == 1) { return userName.stream().map(name -> { if (name.contains(chineseCharacters)) { return name; } return null; }).filter(Objects::nonNull).collect(Collectors.toList()); } //如果用户输入的事多个字符, 则按照谐音去搜索, 既输入长三 可以搜索出张三 if (chineseCharacters.length() > 1) { //将汉字转换为拼音 List pinyin = pinYinConvertNoInitial(chineseCharacters); //循环拼音模糊搜索, 将返回值扁平流组装为一个数组 return pinyin.stream().flatMap(user -> Objects.requireNonNull(pinyinFuzzySearch(user, userName)).stream()).distinct().collect(Collectors.toList()); } return null; } /** * 拼音模糊搜索 * * @param pinyin 用户输入的拼音 * @param userName 需要匹配的名称集合 * @return 匹配成功用户名称 */ public static List pinyinFuzzySearch(String pinyin, List userName) { String lowercasePinYin = pinyin.toLowerCase(); if (CollectionUtil.isEmpty(userName)) { log.info("userName为空"); return null; } //存储 Map pinYinMap = new HashMap(); for (String name : userName) { //将姓名转换为 拼音首字母 + 拼音 String pinYin = pinYinConvert(name); pinYinMap.put(pinYin, name); } List userNameList = new ArrayList(); //循环对拼音进行模糊匹配 pinYinMap.forEach((py, name) -> { if (py.contains(lowercasePinYin)) { userNameList.add(name); } }); return userNameList; } /** * 判断当前字符串的类型 * * @param userName 用户名称 * @return 1是汉字 2是字母 3既是汉字也是字母 */ public static int determineStringType(String userName) { if (userName.matches("[\\u4E00-\\u9FA5]+")) { log.info("字符串由汉字组成:{}", userName); return CHINESE_CHARACTER; } else if (userName.matches("[a-zA-Z]+")) { log.info("字符串由字母组成:{}", userName); return PIN_YIN; } else { log.info("字符串既包含汉字又包含字母:{}", userName); return WHOLE; } } public static String convertToChinese(String str) { String pattern = ".*\\d+.*"; // 包含数字的正则表达式 if (str.matches(pattern)) { str = str.replaceAll("0", "零") .replaceAll("1", "一") .replaceAll("2", "二") .replaceAll("3", "三") .replaceAll("4", "四") .replaceAll("5", "五") .replaceAll("6", "六") .replaceAll("7", "七") .replaceAll("8", "八") .replaceAll("9", "九"); } return str; // 返回修改后的值 } public static List numberToChineseCharacters(List userName) { List list = new ArrayList(); for (String str : userName) { list.add(convertToChinese(str)); } return list; } /** * 模糊查询 * * @param name 用户输入的拼音 * @param userName 需要匹配的名称集合 */ public static List fuzzyQuery(String name, List userName) { String convertName = convertToChinese(name); List convertUserName = numberToChineseCharacters(userName); //判断当前字符串的类型 int state = determineStringType(convertName); //判断用户输入的是否是 汉字 if (state == CHINESE_CHARACTER) { return chineseCharactersFuzzySearch(convertName, convertUserName); } //判断用户输入的是否是 拼音 if (state == PIN_YIN) { return pinyinFuzzySearch(convertName, convertUserName); } //判断用户输入的 即输入拼音也输入汉字 if (state == WHOLE) { return null; } return null; } /** * 将中文汉字替换为阿拉伯数字 * @param input * @return */ public static String replaceChineseNumber(String input) { String[] chineseNumbers = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "零"}; String[] arabicNumbers = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "0"}; for (int i = 0; i < chineseNumbers.length; i++) { input = input.replace(chineseNumbers[i], arabicNumbers[i]); } return input; } } 🐛 注意

搜索阿拉伯数字的业务逻辑: 假设存储的用户姓名为"张三2", 用户输入的内容为3, 在后台的逻辑是需要将"张三2"用正则表达式替换为"张三二"然后在进行后续的拼音处理, 到最后的时候需要开发者手动的调用replaceChineseNumber(String input)方法将中文汉字替换为阿拉伯数字, 此时匹配上的数据是两条"张三2","张三二" 其中有一条数据是冗余的, 这块开发者需要对应自己的业务进行自行处理



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有