java 拼音搜索功能设计与实现

您所在的位置:网站首页 查找字的读音的软件 java 拼音搜索功能设计与实现

java 拼音搜索功能设计与实现

#java 拼音搜索功能设计与实现| 来源: 网络整理| 查看: 265

前言

在搜索场景中,有下面这种需求,即搜索用户的中文拼音,简拼或全拼,甚至拼音的前几位字母时,能够快速检索出来,如下所示

在这里插入图片描述

我们希望得到下面这种效果 在这里插入图片描述 这就是一个典型的利用拼音检索功能实现对用户数据搜索的业务,这个看起来简单但实用的功能如何实现呢?

实现思路分析

1、借助es

如果您的用户数据是放在es里面的,那么在存储用户数据的时候,考虑为用户的索引中冗余一个用户中文名称的拼音字段,那么检索的时候,可以将这个拼英字段作为搜索条件进行搜索,es对拼英提供分词的能力

2、直接在mysql中做

如果您的用户数据直接存在mysql表中,同样,冗余出一个拼音字段来,查询的时候可以考虑mysql自身的模糊匹配,或者locate函数,将符合条件的数据查询出来

以上是2种基本实现此功能的思路,但从中,可以捕捉到一个关键的信息就是,需要在入库(es或mysql)的时候,生成一个账户对应的拼音字段,这个转换是关键,这里就需要借助一个外部的组件,本文采用pinyin4j

功能设计点

有了上面的基础实现思路,这还不够,还需要考虑的点包括,

该搜索功能支持哪些场景的搜索,如前缀拼音?中间任何一个拼音?全拼?中文名字简拼?如果中文姓名是多音字,又该如何?

在调研了一部分真实用户的实际需求场景后发现下面的线索:

使用拼音检索希望缩小检索的范围,用户有时候会忘记目标检索对象的全名,只记得姓氏更偏向于姓氏前几位,即输入姓氏的某几位,就能给出一批大致符合条件的用户列表希望一些多音字的名字,也可以支持搜索

基于上面已知的业务信息,下面就用代码实现这个功能吧

功能实现步骤

前置准备

准备一张用户表,注意需要冗余一个拼音字段搭建一个springboot工程 CREATE TABLE `db_user` ( `user_id` varchar(32) NOT NULL COMMENT '用户ID', `tenant_id` varchar(32) NOT NULL COMMENT '租户ID', `realname` varchar(64) DEFAULT NULL COMMENT '昵称,表示用户真实姓名', `account` varchar(64) DEFAULT NULL COMMENT '帐号', `email` varchar(64) DEFAULT NULL COMMENT '邮箱', `mobile` varchar(32) DEFAULT NULL COMMENT '手机号', `passwd` varchar(256) NOT NULL COMMENT '密码', `skin` varchar(36) DEFAULT NULL COMMENT '皮肤', `key_word` varchar(36) DEFAULT NULL COMMENT '关键词', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1、引入pinyin4j依赖

com.belerweb pinyin4j 2.5.0

紧接着我们需要考虑的是,在什么样的场景下,需要将这个用户名称的拼音字段存进去呢?很容易想到,新增一个用户,或者修改用户信息的时候,所以需要提供2个基础的接口,接口实现本身并不难,也就是入库的操作

public String save(DbUser dbUser) { DbUser insertUser = new DbUser(); String userId = UUIDUtils.random(); BeanUtils.copyProperties(dbUser,insertUser); insertUser.setUserId(userId); //设置拼音字段 setKeyWordField(insertUser ); dbUserMapper.insert(insertUser); return "success"; }

重点考虑的是,保存到key_word 这个字段的拼音存储姓氏,即 realname ——> key_word 的映射 ,那么就需要使用到pinyin4j的提供的相关api做转换操作了,所以接下来,我们需要提供相关的工具类,对生成key_word 的数据做转换

这个key_word 里面要存储什么样的数据呢?结合上文的业务分析,这里为了后续支持的搜索的方式更丰富,考虑存储的格式如下,以 : 黄小斌 这个名字为例,最后希望转换得到的结果是: huangxiaobin,hxb,即全拼和简拼,为了提升姓氏的检索效率,在将姓氏前缀也提取出来一起拼进去,那么最后的结果是: huangxiaobin,hxb,huang ,中间以逗号分割

2、转换工具类

package com.congge.util; import com.alibaba.dubbo.common.utils.CollectionUtils; import lombok.extern.slf4j.Slf4j; 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 net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; import org.apache.commons.lang3.StringUtils; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 中文名字转拼音工具类 * * @author zhangcy * @date 2021-11-04 */ @Slf4j public class PinYinUtils { private final static int[] li_SecPosValue = {1601, 1637, 1833, 2078, 2274, 2302, 2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858, 4027, 4086, 4390, 4558, 4684, 4925, 5249, 5590}; private final static String[] lc_FirstLetter = {"a", "b", "c", "d", "e", "f", "g", "h", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "w", "x", "y", "z"}; /** * 取得给定汉字串的首字母串,即声母串 * * @param str 给定汉字串 * @return 声母串 */ public static String getAllFirstLetter(String str) { if (str == null || str.trim().length() == 0) { return ""; } String _str = ""; for (int i = 0; i < str.length(); i++) { _str = _str + getFirstLetter(str.substring(i, i + 1)); } return _str; } /** * 取得给定汉字的首字母,即声母 * * @param chinese 给定的汉字 * @return 给定汉字的声母 */ public static String getFirstLetter(String chinese) { if (chinese == null || chinese.trim().length() == 0) { return ""; } chinese = conversionStr(chinese, "GB2312", "ISO8859-1"); if (chinese.length() > 1) // 判断是不是汉字 { int li_SectorCode = (int) chinese.charAt(0); // 汉字区码 int li_PositionCode = (int) chinese.charAt(1); // 汉字位码 li_SectorCode = li_SectorCode - 160; li_PositionCode = li_PositionCode - 160; int li_SecPosCode = li_SectorCode * 100 + li_PositionCode; // 汉字区位码 if (li_SecPosCode > 1600 && li_SecPosCode < 5590) { for (int i = 0; i < 23; i++) { if (li_SecPosCode >= li_SecPosValue[i] && li_SecPosCode < li_SecPosValue[i + 1]) { chinese = lc_FirstLetter[i]; break; } } } else // 非汉字字符,如图形符号或ASCII码 { chinese = conversionStr(chinese, "ISO8859-1", "GB2312"); chinese = chinese.substring(0, 1); } } return chinese; } /** * 字符串编码转换 * * @param str 要转换编码的字符串 * @param charsetName 原来的编码 * @param toCharsetName 转换后的编码 * @return 经过编码转换后的字符串 */ public static String conversionStr(String str, String charsetName, String toCharsetName) { try { str = new String(str.getBytes(charsetName), toCharsetName); } catch (UnsupportedEncodingException ex) { System.out.println("字符串编码转换异常:" + ex.getMessage()); } return str; } /** * 首字母大写 * * @param name 参数中文字符串 * @return result * @throws {@link BadHanyuPinyinOutputFormatCombination} */ public static String getChinesePinyinFromName(String name) { String result = null; try { HanyuPinyinOutputFormat pyFormat = new HanyuPinyinOutputFormat(); pyFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); pyFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); pyFormat.setVCharType(HanyuPinyinVCharType.WITH_V); result = PinyinHelper.toHanyuPinyinString(name, pyFormat, ""); } catch (Exception e) { e.printStackTrace(); } return result; } public static boolean isChineseName(String name) { boolean result = true; if (StringUtils.isNotEmpty(name)) { String[] strChars = name.split(""); for (String singleStr : strChars) { if (!isContainChinese(singleStr)) { result = false; break; } } } return result; } public static boolean isContainChinese(String str) { Pattern p = Pattern.compile("[\u4e00-\u9fa5]"); Matcher m = p.matcher(str); if (m.find()) { return true; } return false; } public static String getChineseFirstPingYingName(String str) { String[] split = str.split(""); return PinYinUtils.getChinesePinyinFromName(split[0]); } public static String convert(String chineseName) { String nameVar1 = getChinesePinyinFromName(chineseName); String nameVar2 = getAllFirstLetter(chineseName); String nameVar3 = getChineseFirstPingYingName(chineseName); String result = nameVar1 + "," + nameVar2 + "," + nameVar3; return result; } public static boolean isMixedStr(String realname) { String[] splitStr = realname.split(""); List allStrs = Arrays.asList(splitStr); List allLastStr = new ArrayList(); boolean hasChinese = false; for (String single : splitStr) { if (isChineseName(single)) { hasChinese = true; } else { allLastStr.add(single); } } if (hasChinese) { if (CollectionUtils.isNotEmpty(allStrs) && CollectionUtils.isNotEmpty(allLastStr) && allLastStr.size() < allStrs.size()) { hasChinese = true; } } return hasChinese; } public static void main(String[] args) { PinYinUtils pinYinUtils = new PinYinUtils(); String chineseName = "胡"; String nameVar1 = pinYinUtils.getChinesePinyinFromName(chineseName); String nameVar2 = pinYinUtils.getAllFirstLetter(chineseName); String nameVar3 = pinYinUtils.getChineseFirstPingYingName(chineseName); System.out.println(nameVar1); System.out.println(nameVar2); System.out.println(nameVar3); } private static PinYinMultiCharactersUtils pinYinMultiCharactersUtils = new PinYinMultiCharactersUtils(); /** * 如果是中文何字符串等混合过来的,只需原样解析,比如:111董aaa飞飞333 ,解析为:111dongaaafeifei333 * * @param realname * @return */ public String getMixPinyinStr(String realname) { if (StringUtils.isEmpty(realname)) { return null; } String[] splitStr = realname.split(""); StringBuilder stringBuilder = new StringBuilder(); int firstIndex = 0; for (String single : splitStr) { if (isChineseName(single)) { //只有第一个中文多音字做解析 if (firstIndex == 0 && pinYinMultiCharactersUtils.isMultiChineseWord(single)) { String chinesePinyinFromName = pinYinMultiCharactersUtils.getMultiCharactersPinYin(single); stringBuilder.append(chinesePinyinFromName); continue; } String chinesePinyinFromName = getChinesePinyinFromName(single); stringBuilder.append(chinesePinyinFromName); firstIndex++; } else { stringBuilder.append(single); } } return stringBuilder.toString(); } }

关于工具类中的一些方法,通过注释想必大家也能看懂,下面要重点说下,如何使用这个工具类呢?还是回到上面那个saveUser的方法中,如何设置这个keyWord的属性值上面来,请看下面这个方法,我们以这个方法为例做深入的剖析

private void setKeyWordField(DbUser userRequest) { if(StringUtils.isEmpty(userRequest.getRealname())){ return; } /** * 1、pinYinUtils.isChineseName 判断传入过来的名称是否是中文呢?如果全部是中文的话做基础的解析 * 2、pinYinUtils.convert 做拼音转换 * 3、pinYinMultiCharactersUtils.getMultiCharactersPinYin 如果名字中的姓氏是多音字时,还需要做一下特别处理 * 4、如果用户名中不全是中文,比如: 周小斌_bank_1 ,类似这样的,或者 : bank_1_周小斌 ,只转换其中的中文,不改变整个字符串的顺序 */ if (pinYinUtils.isChineseName(userRequest.getRealname())) { String originalConvert = pinYinUtils.convert(userRequest.getRealname()); String multiConvertResult = pinYinMultiCharactersUtils.getMultiCharactersPinYin(userRequest.getRealname()); if(StringUtils.isNotEmpty(multiConvertResult)){ userRequest.setKeyWord(originalConvert.concat(",").concat(multiConvertResult)); return; } userRequest.setKeyWord(originalConvert ); }else { //如果不全部是中文,即除了中文之外,还有其他字符混在一起的话,这种才做解析 if(pinYinUtils.isMixedStr(userRequest.getRealname())){ userRequest.setKeyWord(pinYinUtils.getMixPinyinStr(userRequest.getRealname())); } } }

参考其中的4条解释说明,

pinYinUtils.isChineseName 判断传入过来的名称是否是中文呢?如果全部是中文的话做基础的解析pinYinUtils.convert 做拼音转换pinYinMultiCharactersUtils.getMultiCharactersPinYin 如果名字中的姓氏是多音字时,还需要做一下特别处理如果用户名中不全是中文,比如: 周小斌_bank_1 ,类似这样的,或者 : bank_1_周小斌 ,只转换其中的中文,不改变整个字符串的顺序

该方法即把上面拼音转换工具类中的所有方法全部调起来使用了,工具类方法本身并不太难,但是需要结合自身的业务场景合理使用

关于多音字处理

在上午中,我们还提到,在实际的用户名称中,存在那些多音字的场景,比如: 单,正常解析出来就是 “dan” ,很明显这是不符合要求的,姓氏中应该解析为 “shan” (忽略 chan) ,或 “解” ,就应该解析为 “xie” ,这样分析之后发现,解析 “解小龙” 这个名字时,如果按照上面的工具类,解析出来的应该是 : jiexiaobin,jxb,如果再经过多音字的解析,还应该解析出 “xiexiaobin” 这个拼音,那么完整的冗余 keyWord字段值为:jiexiaobin,jxb,jie,xiexiaobin(考虑到使用系统的用户并不知道哪些是多音字)

解析多音字比较常用的做法是,维护一个常用的多音字的字典对照表,这个和 es中维护的停用词字典很像,这里直接列出提供参考,后续可以手动添加

在这里插入图片描述

a#阿 ao#拗口/违拗/拗断/执拗/拗口/拗口风/拗口令/拗曲/拗性/拗折/警拗 ai#艾 bang#膀/磅/蚌 ba#扒 bai#叔伯/百/柏杨/㧳/梵呗/呗佛/呗音/呗唱/呗偈/呗声/呗赞/赞呗 bao#剥皮/薄/暴/堡/曝 bei#呗 beng#蚌埠 bi#复辟/臂/秘鲁/泌阳 bing#屏息/屏弃/屏气/屏除/屏声 bian#扁/便/便宜坊 bo#薄荷/单薄/伯/泊/波/柏/萝卜/孛 bu#卜/柨 can#参 cang#藏/欌 cen#参差 ceng#曾/噌 cha#差/刹那/宝刹/一刹/查/碴/喳喳/喀喳 chai#公差/差役/专差/官差/听差/美差/办差/差事/差使/肥差/当差/钦差/苦差/出差 chan#颤/单于/禅 chang#长/厂 chao#朝/嘲/焯 che#工尺/车 chen#称职/匀称/称心/相称/对称 cheng#称/乘/澄/噌吰/橙 秤/盛满/盛器/盛饭 chu#畜 chui#椎心 chuai#揣 chuan#传 chi#匙/尺/吃 chong#重庆/重重/虫 chou#臭/帱 chuang#经幢 chuo#绰 ci#参差/鳞差/伺候/龟兹 cuan#攒聚/攒动/攒集/攒宫/攒所 cuo#撮儿/撮要/撮合 da#大/嗒 dao#叨/帱载/帱察 dai#大夫 dan#单/弹/掸/澹 dang#铛 de#的/得 di#堤/底/怎的/有的/目的/标的/打的/的确/有的放/的卢/矢之的/言中的/语中的/的士/地/提防/快的/美的 diao#蓝调/调调/音调/论调/格调/调令/低调/笔调/基调/强调/声调/滥调/老调/色调/单调/腔调/跑调/曲调/步调/语调/主调/情调 ding#丁 du#读/都/度 dou#全都/句读 duo#舵/测度/忖度/揣度/猜度 dun#粮囤/盾/顿/沌/敦 e#阿谀/阿胶/阿弥/恶/擜 er#儿 fan#番 feng#冯 fei#婔 fo#佛 fu#仿佛/果脯/罘/莩 fou#否 fiao#覅 ga#咖喱/伽马/嘎/戛纳 gai#盖 gao#告 gang#扛鼎 ge#革/蛤蚧/文蛤/蛤蜊/咯 gei#给 geng#脖颈 gong#女红/共 gu#谷/中鹄/鼓 gui#龟/柜/硅/倭傀/傀异/傀然/傀垒/傀怪/傀卓/傀奇/傀伟/傀民/傀俄/琦傀/奇傀 gua#呱 guan#纶巾/东莞 guang#广 ha#蛤/哈/虾蟆 hai#还/嗨/咳声/咳笑 hao#貉子/貉绒 hang#夯/总行/分行/支行/行业/排行/行情/央行/商行/外行/银行/中行/交行/招行/农行/工行/建行/商行/酒行/麻行/琴行/行业/同行/行列/行货/行会/行家/巷道/引吭/扼吭/批吭/搤吭/高吭/喉吭/咔吭/絶吭/吭嗌/吭咽/吭首 he#和/合/核/鶴/猲 heng#道行/涥 hu#鹄/水浒/嗀/唬 hua#滑/呚/椛 huan#归还/放还/奉还/圜 hui#会/浍河/媈/灳/哕/瑗珲 hong#红/虹 huo#软和/热和/暖和 hun#尡/珲 ji#病革/给养/自给/给水/薪给/给予/供给/稽/缉/藉/奇数/亟/诘屈/荠菜/愱 jia#雪茄/伽/家/价/贾/戛 jian#见/浅浅 jiang#降 jiao#嚼舌/嚼字/嚼蜡/角/剿/饺/脚/蕉/矫/睡觉/侥/校对/校验/校正/校准/审校/校场/校核/校勘/校订/校阅/校样 jie#慰藉/蕴藉/诘/媘/煯 jin#矜/劲/禁 jing#颈/景/强劲/劲风/劲旅/劲敌/劲射/苍劲/遒劲/劲草 jiong#炅 ju#咀/居/桔/句/婮 jun#均 juan#棚圈/圈养/猪圈/羊圈 jue#主角/角色/旦角/女角/丑角/角力/名角/配角/嚼/觉/䏐 jun#龟裂/俊 ka#咖/卡/喀 kai#楷 kang#扛 ke#咳/壳 keng#吭 kuai#会计/财会/浍 kui#傀 kuo#括 la#癞痢/腊/蜡 lai#癞疮/癞子/癞蛤/癞皮 lao#积潦/络子/落枕/落价/粩/姥 le#乐/勒/了 lei#勒紧 lo#然咯 lou#佝偻/泄露/露面/露脸/露骨/露底/露馅/露一手/露相/露马脚/露怯 long#里弄/弄堂/泷 li#跞/礼/櫔/栃 liao#了解/了结/明了/了得/末了/未了/了如/潦/撩 liang#靓/俩 lie#挘 lin#崊 ling#霗/令 liu#六/遛 lu#碌/陆/露 luo#络/落/漯/囖/洜/泺 lv#率/绿 lve#鋢/稤 lun#纶 ma#嫲/抹布/抹脸/抹桌子/摩挲 mai#埋 man#埋怨/蔓 mai#脉 mang#氓/芒 mao#冒 me#嚒 men#椚 meng#群氓/盟/癦 mei#没/旀 mo#淹没/没收/出没/沉没/没落/吞没/覆没/没入/埋没/鬼没/隐没/湮没/辱没/脉脉/模/摩/抹 mou#绸缪/牟 mi#秘/泌尿/分泌/谜/檷枸 mian#渑 ming#掵 miu#谬/谬论/纰缪 mu#大模/字模/模板/模样/模具/装模/模子/牟尼/子牟/夷牟/悬牟/相牟/头牟/宾牟/曹牟/岑牟/兜牟/卢牟/弥牟/牟食/牟槊/牟衫/牟光/牟牟/牟甲 na#哪/娜/那 nao#臑 nan#南 ne#哪吒/呢 nei#氞 neus#莻 nong#弄/燶 ni#毛呢/花呢/呢绒/线呢/呢料/呢子/呢喃/溺/檷 niao#尿/鸟/便溺 nian#粘膜/粘度/粘土/粘合剂/粘液/粘稠/粘合/粘着/粘结/粘性/粘附/不粘锅/粘糊/粘虫/粘聚/粘滞/焾/哖 niang#酿 nin#脌 ning#倿/拧 niu#拗/汼 nu#努 nuo#婀娜/袅娜/喏 nv#女 nve#疟/硸 o#喔/筽 ou#膒 pa#扒手/扒窃/扒外/扒分/扒糕/扒灰/扒犁/扒龙/扒搂/扒山虎/扒艇 pai#派/迫击/迫击炮 pao#刨/炮/萢 pan#番禺 pang#胖/膀/磅 pei#蓜 pi#辟/否极/臧否/龙陂/芘 pian#扁舟/便宜/魸 piao#朴姓/饿莩/饥莩/葭莩 pin#穦 ping#屏/苹/冯河 po#湖泊/血泊 /迫/朴刀/坡/陂 pu#一曝十寒/里堡/十里堡/脯/朴/曝晒/瀑/埔 qi#期/其/泣/祇 qiu#龟兹/湭 qi#稽首/缉鞋/栖/奇/漆/齐 qia#卡脖/卡子/关卡/卡壳/哨卡/边卡/发卡/峠 qiao#雀盲/雀子/地壳/甲壳/躯壳 qian#纤/乾/浅 qiang#强/㛨/㩖/䅚/䵁 qie#茄/趔趄/聺/籡 qin#亲/沁 qing#干亲/亲家 qiong#熍 qu#区/趣/爠 quan#圈/券 que#雀/炔 re#声喏/唱喏 rong#嬫 ruo#若/嵶 saeng#栍 sang#槡 sai#塞/嘥 sao#螦 se#堵塞/搪塞/茅塞/闭塞/鼻塞/梗塞/阻塞/淤塞/拥塞/哽塞/色 sha#莎/刹车/急刹/厦/杉木/杉篙 shai#色子 shao#勺/红苕 shan#姓单/单/单县/杉/敾/禅让/受禅/禅变/禅代/禅诰 shang#衣裳 she#拾级/折本/射/蛇 shen#沙参/野参/参王/人参/红参/丹参/山参/海参/鹿参/什么/身/沈/桑椹/食椹/烂椹/木椹 sheng#野乘/千乘/史乘/省/晟/盛/陹/渑水 shi#钥匙/什/识/似的/食/石/氏/拾/适/瑡 shiwa#瓧 shuai#表率/率性/率直/率真/粗率/率领/轻率/直率/草率/大率/坦率/衰 shuang#泷水/鏯 shu#属/数/术/熟 shui#游说 shuo#数见/说 si#伺/似/思 sou#蓃/摗 su#宿/鯂 sui#尿泡 ta#拓片/拓印/拓本/拓墨/拓写/拓手/拓工/碑拓/疲沓/拖沓/杂沓/沓/塔/鸿塔 tang#汤/镗 tao#陶 tan#反弹/弹性/弹簧/弹力/弹奏/弹跳/弹指/弹劾/弹唱/弹射/弹性体/吹弹/评弹/乱弹琴/弹压/弹指/弹簧/弹冠/弹雀/弹雀/弹丝/弹丸/澹台 te#脦 teng#虅 ti#提/体 tiao#调/苕 ting#町/听 tong#通 tu#迌 tuan#湪 tui#褪 tuo#拓/袥 tun#囤/屯 wei#尾/蔚/圩堤/圩垸/圩田/圩子/赶圩/歌圩 weng#攚 wu#无/可恶/交恶/好恶/厌恶/憎恶/嫌恶/痛恶/深恶/兀 wan#藤蔓/枝蔓/根蔓/蔓草/瓜蔓/蔓儿/莞/万/百万/皖 wang#亡 wai#崴 xia#虾/吓/夏/厦门/厦大/唬杀 xi#栖/系/蹊/洗/溪/戏/焁/铣/褶衣/褶裤 xiao#校/切削/削面/刀削/刮削 xian#纤细/光纤/纤巧/纤柔/纤小/纤维/纤瘦/纤纤/化纤/纤秀/棉纤/纤尘/铣铁/金铣 xiang#投降/巷 xie#解/解数/出血/采血/换血/血糊/尿血/淤血/放血/血晕/血淋/便血/吐血/咯血/叶韵/蝎/蝎子/邪/猲猲 xin#嬜/邤 xiu#铜臭/乳臭/成宿/星宿/璓 xin#馨/信/鸿信 xing#深省/省视/内省/不省人事/省悟/省察/行/荥 xiong#匂 xu#牧畜/畜产/畜牧/畜养/并畜/畜锐/吁/圩/浒 xuan#箮 xue#削/血/樰 xun#荨/寻 ya#琊 yao#钥/耀/曜/佋侥/侥觎/侥僺/侥利/侥傒/侥觊/侥会/侥滥/侥望/侥求/侥竞/侥薄/侥躐/侥取/侥奇/侥忝/侥速/侥冀/侥冒/疟子 yan#咽/殷红/朱殷/腌/烟/曕 ye#液/抽咽/哽咽/咽炎/呜咽/幽咽/悲咽/叶/葉/璍/潱/拽步/拽扶/拽扎 yi#自艾/遗/屹/嬄/噫 yin#殷/栶 ying#荥经/緓/灜 yo#杭育 yong#涌/硧 you#牗 yu#余/呼吁/吁请/吁求/育/熨帖/熨烫/於 yuan#员/茒/圜丘 yun#熨 yue#约/乐音/器乐/乐律/乐章/音乐/乐理/民乐/乐队/声乐/奏乐/弦乐/乐坛/管乐/配乐/乐曲/乐谱/锁钥/密钥/乐团/乐器/嬳/咽哕/唾哕/发哕/干哕/哕吐/哕饭/哕呕/哕息/哕厥/哕噫/哕逆/哕咽/哕骂/哕心/哕喈/口哕/呕哕 za#绑扎/结扎/包扎/捆扎/咱家 zan#攒/咱 zang#宝藏/藏历/藏文/藏语/藏青/藏族/藏医/藏药/藏蓝/西藏 zai#牛仔/龟仔/龙仔/鼻仔/羊仔/仔仔/麻仔/麵包仔/麦旺仔/鸿仔/煲仔/福仔/畠 zao#栆 ze#择 zeng#曾国藩/曾孙/曾祖父/曾祖/曾祖母/曾孙女/曾巩/囎/缯 zong#综/繌 zha#扎/柞狭/柞薪/柞子/柞鄂/柞叶/柞撒/槱柞/一柞/五柞宫/五柞/雠柞/芟柞/蜡祭/喳 zhai#宅/夈/择席/择菜 zhan#粘 zhang#列车长/行长/村长/镇长/乡长/区长/县长/市长/省长/会长/班长/排长/连长/营长/团长/旅长/师长/军长/委员长/局长/厅长/所长/部长/组长/生长/长大/长高/长个/ zhao#朝朝/明朝/朝晖/朝夕/朝思/今朝/朝气/朝三/朝秦/朝霞/鹰爪/龙爪/魔爪/爪牙/着急/着迷/着火/怎么着/正着/着凉/一着/犯不着/着数/这么着/犯得着/着慌/着忙/数得着/龙爪槐/嘲哳/嘲惹 zhe#折/着/褶 zhen#殝/椹 zhi#标识/吱/殖/枝/方祇/后祇/皇祇/黄祇/皇地祇/金祇/祇树/月氏 zhong#重/种 zhou#粥 zhu#属意/著/駯 zhua#爪子 zhuai#拽 zhuan#芈月传/外传/传记/自传/正传/小传/评传/传略/别传 zhui#椎/隹 zhuo#执著/着装/着落/着意/着力/附着/着笔/胶着/着实/衣着/着眼/着想/着重/穿着/执着/着墨/着实/沉着/着陆/着想/着色/焯见/焯烁/辉焯 zhuang#幢房/一幢/幢楼/庒 zi#仔/兹 zu#足 zuo#柞/穝

最后再提供一个解析多音字的工具类

package com.congge.utils.pyin; 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.exception.BadHanyuPinyinOutputFormatCombination; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 处理多音字的扩展工具类 * * @author zhangcy * @date 2021-12-02 */ public class PinYinMultiCharactersUtils { private static final Logger logger = LoggerFactory.getLogger(PinYinMultiCharactersUtils.class); private static Map pinyinMap = new HashMap(); private static Map otherSpecialWord = new HashMap(); static { //这里如果apollo上面没有配置任何的值,默认初始化一些常用的 otherSpecialWord.put("解", Arrays.asList("xie")); otherSpecialWord.put("查", Arrays.asList("zha")); otherSpecialWord.put("单", Arrays.asList("shan")); otherSpecialWord.put("朴", Arrays.asList("piao")); otherSpecialWord.put("区", Arrays.asList("ou")); otherSpecialWord.put("仇", Arrays.asList("qiu")); otherSpecialWord.put("阚", Arrays.asList("kan")); otherSpecialWord.put("种", Arrays.asList("chong")); otherSpecialWord.put("盖", Arrays.asList("ge")); otherSpecialWord.put("繁", Arrays.asList("po")); } public static String toPinyin(String str) { try { initPinyin("/duoyinzi.dic.txt"); String py = convertChineseToPinyin(str); System.out.println(str + " = " + py); return py; } catch (Exception e) { logger.error("convert pinyin error,e : {}", e); return null; } } /** * 通过拆分名字的方式 获取多音字的名字的完整拼音 * * @param chinese * @return */ public static String getMultiCharactersPinYin(String chinese) { if (StringUtils.isEmpty(chinese)) { return null; } String result = null; if (chinese.length() >= 2) { String[] nameElements = chinese.split(""); String firstName = nameElements[0]; if (!isMultiChineseWord(firstName)) { return null; } String secondName = null; StringBuilder sb = new StringBuilder(); for (String str : nameElements) { if (!str.equals(firstName)) { sb.append(str); } } secondName = sb.toString(); //获取多音字的拼音 String partOne = PinYinMultiCharactersUtils.toPinyin(firstName); String partTwo = PinYinMultiCharactersUtils.toPinyin(secondName); result = partOne.concat(partTwo).toLowerCase(); } else { result = PinYinMultiCharactersUtils.toPinyin(chinese); } return result; } /** * 将某个字符串的首字母大写 * * @param str * @return */ public static String convertInitialToUpperCase(String str) { if (str == null) { return null; } StringBuffer sb = new StringBuffer(); char[] arr = str.toCharArray(); for (int i = 0; i < arr.length; i++) { char ch = arr[i]; if (i == 0) { sb.append(String.valueOf(ch).toUpperCase()); } else { sb.append(ch); } } return sb.toString(); } /** * 判断当前中文字是否多音字 * * @param chinese * @return */ public static boolean isMultiChineseWord(String chinese) { HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); char[] arr = chinese.toCharArray(); for (int i = 0; i < arr.length; i++) { char ch = arr[i]; if (ch > 128) { // 非ASCII码,取得当前汉字的所有全拼 try { String[] results = PinyinHelper.toHanyuPinyinStringArray(ch, defaultFormat); if (results == null) { //非中文 return false; } else { int len = results.length; if (len == 1) { // 不是多音字 return false; } else if (results[0].equals(results[1])) { //非多音字 有多个音,默认取第一个 if (otherSpecialWord.containsKey(chinese)) { return true; } return false; } else { // 多音字 return true; } } } catch (BadHanyuPinyinOutputFormatCombination e) { logger.error("BadHanyuPinyinOutputFormatCombination ,e :{}", e); } } } return false; } /** * 汉字转拼音 最大匹配优先 * * @param chinese * @return */ private static String convertChineseToPinyin(String chinese) { StringBuffer pinyin = new StringBuffer(); HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); char[] arr = chinese.toCharArray(); for (int i = 0; i < arr.length; i++) { char ch = arr[i]; if (ch > 128) { // 非ASCII码 取得当前汉字的所有全拼 try { String[] results = PinyinHelper.toHanyuPinyinStringArray(ch, defaultFormat); if (results == null) { //非中文 return ""; } else { int len = results.length; if (len == 1) { // 不是多音字 String py = results[0]; if (py.contains("u:")) { //过滤 u: py = py.replace("u:", "v"); logger.info("filter u: {}", py); } pinyin.append(convertInitialToUpperCase(py)); } else if (results[0].equals(results[1])) { //非多音字 有多个音,取第一个 if (otherSpecialWord.containsKey(chinese)) { return otherSpecialWord.get(chinese).get(0); } pinyin.append(convertInitialToUpperCase(results[0])); } else { logger.info("多音字:{}", ch); if (otherSpecialWord.containsKey(chinese)) { pinyin.append(otherSpecialWord.get(chinese).get(0)); continue; } int length = chinese.length(); boolean flag = false; String s = null; List keyList = null; for (int x = 0; x < len; x++) { String py = results[x]; if (py.contains("u:")) { py = py.replace("u:", "v"); logger.info("filter u :{}", py); } keyList = pinyinMap.get(py); if (i + 3


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3