随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666)
在实际项目中,经常会遇到汉字转拼音的需求,比如要根据拼音进行模糊查询,比如安卓里面的联系人就是通过拼音进行搜索的,这个时候就需要把汉字转换为拼音,才能进行拼音的模糊匹配,那么,在今天的文章中,介绍一个非常强大的拼音处理库pinyin4j,相信很多人都听说过甚至使用过,在这里,我总结下它的常见用法,并封装成方法,供以后项目方便调用。
我们知道,汉字是有多音字的,我们先从简单的开始分析,先不考虑多音字的情况。
下面介绍第一个封装的方法,获取汉字的拼音
/**
* 获取拼音,多音字只取一种
*
* @param input
* @return
*/
public static String getSpell(String input) {
StringBuffer py = new StringBuffer();
char[] cs = input.trim().toCharArray();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
// 不带声调
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
// 设置大小写
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
// 拼音中的u输出为v,例如lv
format.setVCharType(HanyuPinyinVCharType.WITH_V);
for (char c : cs) {
if (isChinese(c)) {
try {
String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (pinyin != null && pinyin.length > 0) {
py.append(pinyin[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
logger.error("", e);
}
} else {
py.append(c);
}
}
return py.toString();
}
代码非常简单,核心代码是String[] pinyin=PinyinHelper.toHanyuPinyinStringArray(c, format),这就是将汉字转换为拼音的API,这里返回的是所有拼音,本方法中只取第一个拼音来说明,HanyuPinyinOutputFormat是拼音输出格式类,可以设置大小写,是否带声调等等。测试代码:PinyinUtil.getSpell("我是一个好人"),打印结果为woshiyigehaoren,是不是很简单呢
还有一种常用需求,获取拼音的首字母,这个在项目中也使用非常多,既然拼音都获取到了,首字母只需要取第一个字符就可以了,代码如下:
public static String getFirstSpell(String input) {
StringBuffer py = new StringBuffer();
char[] cs = input.trim().toCharArray();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
format.setVCharType(HanyuPinyinVCharType.WITH_V);
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
for (char c : cs) {
if (isChinese(c)) {
try {
String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (pinyin != null && pinyin.length > 0) {
py.append(pinyin[0].charAt(0));
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
logger.error("", e);
}
} else {
py.append(c);
}
}
return py.toString().replaceAll("\\W", "").trim();
}
只需要对刚才使用toHanyuPinyinStringArray获取的拼音取第一个字母就可以了。测试结果:WSYGHR
那么单音字分析了,我们该考虑多音字了,如果换一串汉字再使用上面获取拼音的方法,就可能不是我们想要的效果了,比如PinyinUtil.getFirstSpell("长沙市长"),结果为zhangshashizhang,第一个字就不是我们想要的拼音了。处理方法如下:
public static List<String> getPolyphoneSpell(String input) {
StringBuffer py = new StringBuffer();
char[] cs = input.toCharArray();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (char c : cs) {
if (isChinese(c)) {
try {
// 取得当前汉字的所有全拼
String[] strs = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (strs != null) {
for (int j = 0; j < strs.length; j++) {
py.append(strs[j]);
if (j != strs.length - 1) {
py.append(",");
}
}
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
logger.error("", e);
}
} else {
py.append(c);
}
py.append(" ");
}
return combinePinyin(removeRepeat(py.toString()));
}
这里的处理方式为,将同一个字的多音字用‘,’隔开,不同汉字拼音用空格隔开,得到的效果如下:zhang,chang sha,sha shi zhang,chang,然后进行第二步排重,这里看到了‘沙’字在忽略声调的情况下有两个一样的多音字,排重方法如下:
private static List<Map<String, Integer>> removeRepeat(String pinyins) {
// 去除重复拼音后的拼音列表
List<Map<String, Integer>> l = new ArrayList<>();
// 用于去重
Map<String, Integer> only = null;
String[] all = pinyins.split(" ");
// 遍历每个汉字的拼音
for (String str : all) {
only = new Hashtable<>();
// 拆分单个汉字的多音字拼音
String[] pol = str.split(",");
// 去重处理
for (String s : pol) {
Integer count = only.get(s);
if (count == null) {
only.put(s, new Integer(1));
} else {
only.remove(s);
count++;
only.put(s, count);
}
}
l.add(only);
}
return l;
}
思路很简单,用一个map来存储每个汉字的多音字,重复的就只保留一个。接下来进行第三步,拼音整合,将所有可能性组合起来,比如上面的例子,在排重以后,还有两个多音字,就有四种组合,组合代码方法如下:
private static List<String> combinePinyin(List<Map<String, Integer>> list) {
// 保存组合数据
Map<String, Integer> map = null;
// 遍历每一组集合
for (int i = 0; i < list.size(); i++) {
// 这次与上一次组合的临时Map
Map<String, Integer> temp = new Hashtable<String, Integer>();
// 第一次循环,取集合第一个数据赋值
if (map == null) {
for (String s : list.get(i).keySet()) {
String str = s;
temp.put(str, 1);
}
} else {
// 组合上次与这次的拼音
for (String s : map.keySet()) {
for (String s1 : list.get(i).keySet()) {
String str = s + s1;
temp.put(str, 1);
}
}
// 清理上一次组合数据
if (temp != null && temp.size() > 0) {
map.clear();
}
}
// 保存新组合数据
if (temp != null && temp.size() > 0) {
map = temp;
}
}
List<String> result = new ArrayList<>();
if (map != null) {
for (String str : map.keySet()) {
result.add(str);
}
}
return result;
}
思路也非常简单,用一个map来存储整合的数据,每次遍历将新的数据和之前整合的数据再组装,然后作为新的组合数据,遍历完后map就存储所有整合完的多音字情况。代码有非常详细的注释,相信大家都很容易看懂。然后将所有组合添加到集合返回,方便使用。测试结果如下:[zhangshashichang, changshashichang, zhangshashizhang, changshashizhang]
好,到这里获取多音字拼音介绍完了,获取首字母思路就是一样的了,直接上代码:
public static List<String> getPolyphoneFirstSpell(String input) {
StringBuffer py = new StringBuffer();
char[] cs = input.toCharArray();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (char c : cs) {
if (isChinese(c)) {
try {
// 取得当前汉字的所有全拼
String[] strs = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (strs != null) {
for (int j = 0; j < strs.length; j++) {
// 取首字母
py.append(strs[j].charAt(0));
if (j != strs.length - 1) {
py.append(",");
}
}
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
logger.error("", e);
}
} else {
py.append(c);
}
py.append(" ");
}
return combinePinyin(removeRepeat(py.toString()));
}
测试结果:[cssc, zssz, zssc, cssz]
判断是否为汉字的方法:
public static boolean isChinese(char c) {
return c >= 0x4E00 && c <= 0x9FA5;
}
到这里,pinyin4j的基本使用介绍完了,这个库还有其它非常强大的功能,比如支持声调等等,留着大家继续探究吧。