Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的转换。拼音输出格式可以定制,然而真正的把含有多音字、数字、字母的中文句子转成拼音得到所有的组合情况却有很大难度,我看过很多有关博客或者帖子,被广大网友视为它的短板和不足,很多网友哀声叹气不能真正得到所有组合情况,一部分也只是用简单循环得到中文句子的拼音组合情况的一种,鄙人利用业余时间研究了研究,把研究结果分享 出来,下边将带大家循序渐进把含有多音字、数字、字母的中文句子转成拼音得到所有的组合情况。
char word='长';//待测汉字,多音字 /*直接获取拼音,返回字符串数组,可能有多个,注意:如果传入的非汉字则返回null*/ String[] easyPinyin=PinyinHelper.toHanyuPinyinStringArray(word); for(String s:easyPinyin){ System.out.println("汉字转拼音最简单方式:"+s);//有2个zhang3,chang2,后边的数字代表音调 }
运行结果如下:
汉字转拼音最简单方式:zhang3 汉字转拼音最简单方式:chang2
HanyuPinyinOutputFormat pinyinFormat = new HanyuPinyinOutputFormat(); //创建拼音输入格式类 pinyinFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);//指定格式中的大小写属性为小写 pinyinFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//指定音标格式无音标 pinyinFormat.setVCharType(HanyuPinyinVCharType.WITH_V);//指定用v表示ü String[] formatPinyin=null; try { formatPinyin = PinyinHelper.toHanyuPinyinStringArray(word, pinyinFormat);//获取对应的汉字拼音,不是汉字返回null } catch (BadHanyuPinyinOutputFormatCombination e) {//会抛出异常,捕获异常 //logger.error(e.getMessage()); e.printStackTrace(); } for(String s:formatPinyin){ System.out.println("格式化后的汉字转拼音结果:"+s);//有2个zhang3,chang2,后边的数字代表音调 }
运行结果:
格式化后的汉字转拼音结果:zhang 格式化后的汉字转拼音结果:chang
先定义2个方法,如下:
/** * 获取包含汉字的一段文字的拼音(只获取一种情况),注意如果涉及汉字的多个读音只获取一种,不全部罗列出来 */ public static String getEasyPinyins(String s){ if(s==null){ s="";//防止为null,后边处理时报错 } StringBuilder sb=new StringBuilder(); char[] words=s.toCharArray();//把这段文字转成字符数组 for(char c:words){ sb.append(Pinyin4jTest.getPinyin(c)); } return sb.toString();//转化成字符串返回 } /** * 获取一个字符的拼音(多音字则返回一种情况),非汉字则返回字符本身 */ public static String getPinyin(char word){ HanyuPinyinOutputFormat pinyinFormat = new HanyuPinyinOutputFormat(); //创建拼音输入格式类 pinyinFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);//指定格式中的大小写属性为小写 pinyinFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//指定音标格式无音标 pinyinFormat.setVCharType(HanyuPinyinVCharType.WITH_V);//指定用v表示ü String[] formatPinyin=null; try { formatPinyin = PinyinHelper.toHanyuPinyinStringArray(word, pinyinFormat);//获取对应的汉字拼音,不是汉字返回null } catch (BadHanyuPinyinOutputFormatCombination e) {//会抛出异常,捕获异常 //logger.error(e.getMessage()); e.printStackTrace(); } if(formatPinyin!=null){ return formatPinyin[0];//返回读音,如果多音字自返回一个 }else{ return String.valueOf(word);//非汉字则返回字符本身 } }
测试调用上边写好的getEasyPinyins方法:
String statence="我24岁,java重生,长大!";//定义一个长字符串 System.out.println("句子拼音组合的一种情况:"+Pinyin4jTest.getEasyPinyins(statence));//输出这段文字拼音的一种情况
这是大家利用pin4j把含有多音字、字母数字转成拼音的“唯一”或者常见的方法了,其运行结果如下:
句子拼音组合的一种情况:wo24sui,javazhongsheng,zhangda!
其实遇到多层循环嵌套或者一个2维数组每行取一个元素组合起来的所有组合情况,往往的解决思路就是递归了,pin4j把汉字转成拼音是返回的一个一维数组,如果是多音字这个一维数组里就有多个元素,如果不是多音字就一个元素,而含有多音字的中文句子就是从每个汉字对应的拼音数组取分别取一个组合起来的所有组合情况,进而用递推可以完美解决这个问题,如下,先定义如下几个方法:
/** * 获取一段文字的所有拼音组合情况,以list<String>形式返回 */ public static List<String> getHardPinyins(String s){ if(s==null){ s="";//null时处理,后边处理时报错 } String[][] allPinyins=new String[s.length()][];//存放整个字符串的各个字符所有可能的拼音情况,如果非汉字则是它本身 char[] words=s.toCharArray();//把这段文字转成字符数组 for(int i=0;i<words.length;i++){ allPinyins[i]=Pinyin4jTest.getAllPinyins(words[i]);//每个字符的所有拼音情况 } String[] resultArray=Pinyin4jTest.recursionArrays(allPinyins,allPinyins.length,0);//用递归,求出这个2维数组每行取一个数据组合起来的所有情况 return Arrays.asList(resultArray);//返回数组支持的固定大小的list(asList注意事项详见我的其他博客,可new LinkedList<String>(Arrays.asList()))来实现对结果随意操作 } /** * 获取包含一个字符的拼音(多音字则以数组形式返回多个),非汉字则返回字符本身 */ public static String[] getAllPinyins(char word){ HanyuPinyinOutputFormat pinyinFormat = new HanyuPinyinOutputFormat(); //创建拼音输入格式类 pinyinFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);//指定格式中的大小写属性为小写 pinyinFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//指定音标格式无音标 pinyinFormat.setVCharType(HanyuPinyinVCharType.WITH_V);//指定用v表示ü String[] formatPinyin=null; try { formatPinyin = PinyinHelper.toHanyuPinyinStringArray(word, pinyinFormat);//获取对应的汉字拼音,不是汉字返回null } catch (BadHanyuPinyinOutputFormatCombination e) {//会抛出异常,捕获异常 //logger.error(e.getMessage()); e.printStackTrace(); } if(formatPinyin==null){ formatPinyin=new String[1]; formatPinyin[0]=String.valueOf(word);//返回读音,如果多音字自返回一个 } return formatPinyin; } /** * 用递归方法,求出这个二维数组每行取一个数据组合起来的所有情况,返回一个字符串数组 * @param s 求组合数的2维数组 * @param len 此二维数组的长度,省去每一次递归长度计算的时间和空间消耗,提高效率 * @param cursor 类似JDBC、数据库、迭代器里的游标,指明当前从第几行开始计算求组合数,此处从0开始(数组第一行) * 避免在递归中不断复制剩余数组作为新参数,提高时间和空间的效率 * @return String[] 以数组形式返回所有的组合情况 */ public static String[] recursionArrays(String[][] s,int len,int cursor){ if(cursor<=len-2){//递归条件,直至计算到还剩2行 int len1 = s[cursor].length; int len2 = s[cursor+1].length; int newLen = len1*len2;//上下2行的总共的组合情况 String[] temp = new String[newLen];//存上下2行中所有的组合情况 int index = 0; for(int i=0;i<len1;i++){//嵌套循环遍历,求出上下2行中,分别取一个数据组合起来的所有情况 for(int j=0;j<len2;j++){ temp[index] = s[cursor][i] + s[cursor+1][j]; index ++; } } s[cursor+1]=temp;//把当前计算到此行的所有组合结果放在cursor+1行 cursor++;//游标指向下一行,即上边的数据结果 return Pinyin4jTest.recursionArrays(s,len,cursor); }else{ return s[len-1];//返回最终的所有组合结果 } }
其中Arrays.asList()的用法一定注意的事项或者陷阱,详见我的博文:Array.asList:数组转list时你一定要知道的“陷阱”!
代码上几乎每行都有注释,大家一看便明白了,下边测试上边写好的方法,如下:
String statence="我24岁,java重生,长大!";//定义一个长字符串
System.out.println("句子拼音组合所有情况如下:"); List<String> list=Pinyin4jTest.getHardPinyins(statence); for(String ca:list){ System.out.println(ca); }
运行结果如下:
句子拼音组合所有情况如下: wo24sui,javazhongsheng,zhangda! wo24sui,javazhongsheng,zhangdai! wo24sui,javazhongsheng,changda! wo24sui,javazhongsheng,changdai! wo24sui,javachongsheng,zhangda! wo24sui,javachongsheng,zhangdai! wo24sui,javachongsheng,changda! wo24sui,javachongsheng,changdai!
一切都解决了,over!
转载请注明—作者:Java我人生(陈磊兴) 原文出处:http://blog.csdn.net/chenleixing/article/details/44087541