根据拼音实现模糊匹配工具类

引入坐标

<!--拼音模糊搜索-->
<dependency>
    <groupId>com.belerweb</groupId>
    <artifactId>pinyin4j</artifactId>
    <version>2.5.0</version>
</dependency>

工具类

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
@Component
/**
 * 拼音搜索Trie
 * 接收参数Map<String, String> key 为 id,value 为 name
 * 搜索时,支持拼音首字母搜索,支持拼音全拼搜索
 */
public class PinyinSearchTrie {

    private TrieNode root;

    public PinyinSearchTrie() {
        this.root = new TrieNode();
    }

    // 添加词条到Trie中,词条由 name 和 id 组成
    public void addNamesWithId(Map<String, String> map) throws Exception {
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String id = entry.getKey();
            String name = entry.getValue();
            String fullPinyin = getFullPinyin(name);
            String firstLetters = getFirstLetters(name);

            // 插入全拼和首字母到 Trie 中
            insert(fullPinyin, id);
            insert(firstLetters, id);
        }
    }

    // 插入拼音到 Trie 中
    private void insert(String pinyin, String id) {
        TrieNode node = root;
        for (char c : pinyin.toCharArray()) {
            node = node.children.computeIfAbsent(c, k -> new TrieNode());
        }
        node.isEndOfWord = true;
        node.ids.add(id); // 将 id 存入
    }

    // 根据前缀查找所有匹配的 id
    public List<String> search(String prefix) {
        TrieNode node = root;
        List<String> results = new ArrayList<>();

        // 逐字符查找前缀
        for (char c : prefix.toCharArray()) {
            node = node.children.get(c);
            if (node == null) {
                return results; // 如果找不到前缀,返回空结果
            }
        }

        // 获取以该前缀开头的所有 id
        collectAllIds(node, results);
        return results;
    }

    // 收集以当前节点为根的所有 id
    private void collectAllIds(TrieNode node, List<String> results) {
        if (node.isEndOfWord) {
            results.addAll(node.ids);
        }
        for (char c : node.children.keySet()) {
            collectAllIds(node.children.get(c), results);
        }
    }

    // 获取汉字的全拼
    private String getFullPinyin(String chinese) throws Exception {
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        format.setVCharType(HanyuPinyinVCharType.WITH_V);

        StringBuilder pinyin = new StringBuilder();
        for (char c : chinese.toCharArray()) {
            if (Character.toString(c).matches("[\\u4E00-\\u9FA5]")) {
                String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format);
                if (pinyinArray != null) {
                    pinyin.append(pinyinArray[0]); // 使用第一个拼音
                }
            } else {
                pinyin.append(c); // 非中文字符直接添加
            }
        }
        return pinyin.toString();
    }

    // 获取汉字的首字母
    private String getFirstLetters(String chinese) throws Exception {
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        format.setVCharType(HanyuPinyinVCharType.WITH_V);

        StringBuilder firstLetters = new StringBuilder();
        for (char c : chinese.toCharArray()) {
            if (Character.toString(c).matches("[\\u4E00-\\u9FA5]")) {
                String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format);
                if (pinyinArray != null) {
                    firstLetters.append(pinyinArray[0].charAt(0)); // 提取拼音首字母
                }
            } else {
                firstLetters.append(c); // 非中文字符直接添加
            }
        }
        return firstLetters.toString();
    }

    // TrieNode 内部类
    private static class TrieNode {
        Map<Character, TrieNode> children = new HashMap<>();
        List<String> ids = new ArrayList<>(); // 存储对应的 id 列表
        boolean isEndOfWord = false;
    }

    public static void main(String[] args) throws Exception {
        PinyinSearchTrie searchTrie = new PinyinSearchTrie();

        // 模拟数据: id -> name
        Map<String, String> map = new HashMap<>();
        map.put("001", "北京");
        map.put("002", "上海");
        map.put("003", "广州");
        map.put("004", "深圳");
        map.put("005", "杭州市");
        map.put("006", "成都");
        map.put("007", "重庆");
        map.put("008", "武汉");

        // 添加到 Trie 中
        searchTrie.addNamesWithId(map);

        // 根据拼音前缀进行查询
        String query1 = "du";  // 搜索 "成都"无法匹配
        String query2 = "sh";   // 搜索 "上海" 或 "深圳"
        String query3 = "cheng"; // 搜索 "成都" 或 "重庆"

        List<String> result1 = searchTrie.search(query1);
        List<String> result2 = searchTrie.search(query2);
        List<String> result3 = searchTrie.search(query3);

        // 输出查询结果
        System.out.println("搜索 'du' 的ID结果: " + result1);
        System.out.println("搜索 'sh' 的ID结果: " + result2);
        System.out.println("搜索 'cheng' 的ID结果: " + result3);
    }
}

调用示例

Map<String, String> map = list.stream().filter(p -> StrUtil.isNotBlank(p.getPersonName())).collect(Collectors.toMap(PeopleInformationBase::getId, PeopleInformationBase::getPersonName));
pinyinSearchTrie.addNamesWithId(map);
//其中form.getPersonName()是需要模糊匹配的字段
List<String> ids = pinyinSearchTrie.search(form.getPersonName());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值