汉字转拼音

app中有许多场景要对汉字排序,例如通讯录姓名、商品名称、城市名称等等,这些汉字词汇通常是按照拼音排序,所以产生了把汉字转换为拼音的需求。


Android自带库

Android自带的联系人应用,就支持对联系人按照姓名排序,内置汉字转拼音的源码位于路径“packages\providers\ContactsProvider\src\com\android\providers\contacts\HanziToPinyin.java”。该工具类早期的源码,直接把字符集合写在java文件中,这种做法在4.2以上版本不能正常工作。4.2以上的工具源码改为调用底层的jni接口,具体说来,便是HanziToPinyin.java引用了核心库libcore.icu的Transliterator类,Transliterator内部有提供数个native方法。


不管是HanziToPinyin类还是Transliterator类,都属于系统源码,不属于sdk源码,也就是说,app开发无法直接调用这两个类的方法。只能是把这两个类的java文件直接复制到app工程中,才能正常调用其中的api。同时注意,Transliterator.java必须放在名称是libcore.icu的包路径下,因为该类引用了jni接口,而jni接口要求包名、类名、方法名都保持一致才能正常运行,jni的详细说明参见《 Android开发笔记(六十九)JNI实战》。


下面是HanziToPinyin.java的源码:
import android.text.TextUtils;import android.util.Log;import java.util.ArrayList;import libcore.icu.Transliterator;public class HanziToPinyin {    private static final String TAG = "HanziToPinyin";    private static HanziToPinyin sInstance;    private Transliterator mPinyinTransliterator;    private Transliterator mAsciiTransliterator;    public static class Token {        public static final String SEPARATOR = " ";        public static final int LATIN = 1;        public static final int PINYIN = 2;        public static final int UNKNOWN = 3;        public Token() {        }        public Token(int type, String source, String target) {            this.type = type;            this.source = source;            this.target = target;        }        public int type;        public String source;        public String target;    }    private HanziToPinyin() {        try {        mPinyinTransliterator = new Transliterator("Han-Latin/Names; Latin-Ascii; Any-Upper");        mAsciiTransliterator = new Transliterator("Latin-Ascii");        } catch (RuntimeException e) {            Log.w(TAG, "Han-Latin/Names transliterator data is missing," + " HanziToPinyin is disabled");        }    }    public boolean hasChineseTransliterator() {        return mPinyinTransliterator != null;    }    public static HanziToPinyin getInstance() {        synchronized (HanziToPinyin.class) {            if (sInstance == null) {                sInstance = new HanziToPinyin();            }            return sInstance;        }    }    private void tokenize(char character, Token token) {        token.source = Character.toString(character);        // ASCII        if (character < 128) {            token.type = Token.LATIN;            token.target = token.source;            return;        }        // Extended Latin. Transcode these to ASCII equivalents        if (character < 0x250 || (0x1e00 <= character && character < 0x1eff)) {            token.type = Token.LATIN;            token.target = mAsciiTransliterator == null ? token.source :                mAsciiTransliterator.transliterate(token.source);            return;        }        token.type = Token.PINYIN;        token.target = mPinyinTransliterator.transliterate(token.source);        if (TextUtils.isEmpty(token.target) ||            TextUtils.equals(token.source, token.target)) {            token.type = Token.UNKNOWN;            token.target = token.source;        }    }    public String transliterate(final String input) {        if (!hasChineseTransliterator() || TextUtils.isEmpty(input)) {            return null;        }        return mPinyinTransliterator.transliterate(input);    }    public ArrayList<Token> getTokens(final String input) {        ArrayList<Token> tokens = new ArrayList<Token>();        if (!hasChineseTransliterator() || TextUtils.isEmpty(input)) {            return tokens;        }        final int inputLength = input.length();        final StringBuilder sb = new StringBuilder();        int tokenType = Token.LATIN;        Token token = new Token();        for (int i = 0; i < inputLength; i++) {            final char character = input.charAt(i);            if (Character.isSpaceChar(character)) {                if (sb.length() > 0) {                    addToken(sb, tokens, tokenType);                }            } else {                tokenize(character, token);                if (token.type == Token.PINYIN) {                    if (sb.length() > 0) {                        addToken(sb, tokens, tokenType);                    }                    tokens.add(token);                    token = new Token();                } else {                    if (tokenType != token.type && sb.length() > 0) {                        addToken(sb, tokens, tokenType);                    }                    sb.append(token.target);                }                tokenType = token.type;            }        }        if (sb.length() > 0) {            addToken(sb, tokens, tokenType);        }        return tokens;    }    private void addToken(            final StringBuilder sb, final ArrayList<Token> tokens, final int tokenType) {        String str = sb.toString();        tokens.add(new Token(tokenType, str, str));        sb.setLength(0);    }}


下面是Transliterator.java的源码:
package libcore.icu;/** * Exposes icu4c's Transliterator. */public final class Transliterator {  private long peer;  /**   * Creates a new Transliterator for the given id.   */  public Transliterator(String id) {    peer = create(id);  }  @Override protected synchronized void finalize() throws Throwable {    try {      destroy(peer);      peer = 0;    } finally {      super.finalize();    }  }  /**   * Returns the ids of all known transliterators.   */  public static native String[] getAvailableIDs();  /**   * Transliterates the specified string.   */  public String transliterate(String s) {    return transliterate(peer, s);  }  private static native long create(String id);  private static native void destroy(long peer);  private static native String transliterate(long peer, String s);}


下面是调用HanziToPinyin的代码例子:
String pinyin = HanziToPinyin.getInstance().transliterate("我爱你中国");


pinyin4j

pinyin4j是java版本的拼音库,可直接拿到android上使用。pinyin4j与Android自带库相比,多出的功能有:
1、支持展示多音字的不同拼音;
2、支持显示汉字拼音的四个声调;


pinyin4j中常用的就是两个类,一个类HanyuPinyinOutputFormat是用来设置拼音格式的,另一个类PinyinHelper是用来进行转换操作的。

下面是HanyuPinyinOutputFormat的常用方法说明:
setCaseType : 设置拼音的大小写。HanyuPinyinCaseType.UPPERCASE表示大写,HanyuPinyinCaseType.LOWERCASE表示小写。
setToneType : 设置拼音的声调形式。HanyuPinyinToneType.WITHOUT_TONE表示不标声调,HanyuPinyinToneType.WITH_TONE_NUMBER表示在拼音末尾标注数字1-4表示四个声调,HanyuPinyinToneType.WITH_TONE_MARK表示在拼音上方标注四个声调的符号。
setVCharType : 设置特殊拼音ü的的显示格式。HanyuPinyinVCharType.WITH_V表示ü显示为字符v,HanyuPinyinVCharType.WITH_U_AND_COLON表示ü显示为字符u:,HanyuPinyinVCharType.WITH_U_UNICODE表示ü显示为字符ü。
注意:当声调形式设置为符号声调时,setVCharType只能选择HanyuPinyinVCharType.WITH_U_UNICODE,否则运行时会报错“net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination: tone marks cannot be added to v or u:”。

下面是PinyinHelper的常用方法说明:
toHanyuPinyinStringArray : 转为汉字拼音。中国大陆使用
toTongyongPinyinStringArray : 转为通用拼音。中国台湾使用
toWadeGilesPinyinStringArray : 转为威妥玛拼音。
toMPS2PinyinStringArray : 转为注音符号拼音。
toYalePinyinStringArray : 转为耶魯拼音。
toGwoyeuRomatzyhStringArray : 转为国语罗马字。


下面是pinyin4j的一个使用例子代码:
import java.util.HashSet;import java.util.Locale;import java.util.Set;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;public class pinyin4j {public static String makeStringByStringSet(Set<String> stringSet) {StringBuilder str = new StringBuilder();int i = 0;for (String s : stringSet) {if (i == stringSet.size() - 1) {str.append(s);} else {str.append(s + ",");}i++;}return str.toString().toLowerCase(Locale.getDefault());}public static Set<String> getPinyin(String src) {if (src != null && !src.trim().equalsIgnoreCase("")) {char[] srcChar;srcChar = src.toCharArray();// 汉语拼音格式输出类HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();// 输出设置,大小写,音标方式等hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);hanYuPinOutputFormat.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);hanYuPinOutputFormat.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);String[][] temp = new String[src.length()][];for (int i = 0; i < srcChar.length; i++) {char c = srcChar[i];// 是中文或者a-z或者A-Z转换拼音(我的需求,是保留中文或者a-z或者A-Z)if (String.valueOf(c).matches("[\\u4E00-\\u9FA5]+")) {try {temp[i] = PinyinHelper.toHanyuPinyinStringArray(srcChar[i], hanYuPinOutputFormat);} catch (BadHanyuPinyinOutputFormatCombination e) {e.printStackTrace();}} else if (((int) c >= 65 && (int) c <= 90)|| ((int) c >= 97 && (int) c <= 122)) {temp[i] = new String[] { String.valueOf(srcChar[i]) };} else {temp[i] = new String[] { "" };}}String[] pingyinArray = Exchange(temp);Set<String> pinyinSet = new HashSet<String>();for (int i = 0; i < pingyinArray.length; i++) {pinyinSet.add(pingyinArray[i]);}return pinyinSet;}return null;}public static String[] Exchange(String[][] strJaggedArray) {String[][] temp = DoExchange(strJaggedArray);return temp[0];}private static String[][] DoExchange(String[][] strJaggedArray) {int len = strJaggedArray.length;if (len >= 2) {int len1 = strJaggedArray[0].length;int len2 = strJaggedArray[1].length;int newlen = len1 * len2;String[] temp = new String[newlen];int Index = 0;for (int i = 0; i < len1; i++) {for (int j = 0; j < len2; j++) {temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j];Index++;}}String[][] newArray = new String[len - 1][];for (int i = 2; i < len; i++) {newArray[i - 1] = strJaggedArray[i];}newArray[0] = temp;return DoExchange(newArray);} else {return strJaggedArray;}}public static String getPinyinFull(String hanzi) {return makeStringByStringSet(getPinyin(hanzi));}}


下面是Android自带库与pinyin4j转换汉字拼音的截图:






国际语言版本

如同很多windows桌面软件一样,Android也支持将应用发布为多语言版本,即随着手机系统设置的语言变化,app也随之显示对应的语言文本。Android支持对app的字符串和图片分别做国际化处理,字符串国际化只要在res下新建对应语言的values目录就好,比如英文环境的目录命名为“values-en”,中文环境的目录命名为“values-zh”。ADT新建Android项目时,会在res目下自动创建默认环境的values目录,如果某个语言环境没有在项目中定义配置,那么也会使用values下的资源。

Android的图片国际化同理,即在res下新建drawable-zh目录,存放中文环境下的图片;新建drawable-en目录,存放英文环境下的图片。不同分辨率的图片也可以按此规则处理,例如drawable-zh-hdpi表示中文环境下高分辨率的图片目录。


下面是Android多国语言的目录命名列表:

中文(中国大陆):values-zh-rCN
中文(中国台湾):values-zh-rTW
中文(中国香港):values-zh-rHK

英文(美国):values-en-rUS
英文(英国):values-en-rGB
英文(澳大利亚):values-en-rAU
英文(加拿大):values-en-rCA
英文(爱尔兰):values-en-rIE
英文(印度):values-en-rIN
英文(新西兰):values-en-rNZ
英文(新加坡):values-en-rSG
英文(南非):values-en-rZA

阿拉伯文(埃及):values-ar-rEG
阿拉伯文(以色列):values-ar-rIL
保加利亚文: values-bg-rBG
加泰罗尼亚文(西班牙):values-ca-rES
捷克文:values-cs-rCZ
丹麦文:values-da-rDK
德文(奥地利):values-de-rAT
德文(瑞士):values-de-rCH
德文(德国):values-de-rDE
德文(列支敦士登):values-de-rLI
希腊文:values-el-rGR
西班牙文(西班牙):values-es-rES
西班牙文(美国):values-es-rUS
芬兰文:values-fi-rFI
法文(比利时):values-fr-rBE
法文(加拿大):values-fr-rCA
法文(瑞士):values-fr-rCH
法文(法国):values-fr-rFR
希伯来文(以色列):values-iw-rIL
印地文(印度):values-hi-rIN
克罗地亚文:values-hr-rHR
匈牙利文:values-hu-rHU
印度尼西亚文:values-in-rID
意大利文(瑞士):values-it-rCH
意大利文(意大利):values-it-rIT
日文:values-ja-rJP
韩文:values-ko-rKR
立陶宛文:valueslt-rLT
拉脱维亚文:values-lv-rLV
博克马尔文(挪威):values-nb-rNO
荷兰文(比利时):values-nl-BE
荷兰文(荷兰):values-nl-rNL
波兰文:values-pl-rPL
葡萄牙文(巴西):values-pt-rBR
葡萄牙文(葡萄牙):values-pt-rPT
罗马尼亚文:values-ro-rRO
俄文:values-ru-rRU
斯洛伐克文:values-sk-rSK
斯洛文尼亚文:values-sl-rSI
塞尔维亚文:values-sr-rRS
瑞典文:values-sv-rSE
泰文(泰国):values-th-rTH
塔加洛文(菲律宾):values-tl-rPH
土耳其文:values--r-rTR
乌克兰文:values-uk-rUA
越南文:values-vi-rVN





点此查看Android开发笔记的完整目录

更多相关文章

  1. Android懒人库
  2. Android限制EditText只能输入中文、英文、数字
  3. Android(安卓)vs iOS,你应该选择哪一个?
  4. Android、js&html5的基础资料&书籍
  5. Android读取xxx.properties配置文件中文出现乱码解决方法
  6. android中将中文以粗体显示
  7. Android国际化资源 文件夹命名规范
  8. Android中设置中文粗体的方法
  9. Android(安卓)常用RGB值以及中英文名称

随机推荐

  1. android donut 飞行模式分析
  2. Android(安卓)ViewFlipper触摸动画
  3. Android架构组件(Architecture Component
  4. Android Studio 中org.apache.http.legac
  5. IPC——android进程间通信
  6. Android应用最上层悬浮窗实现不依赖于Act
  7. Win7 64位 Android SDK下载和更新失败的
  8. 【Android单元测试系列】真正的异步单元
  9. android 设置apk文件默认安装sdcard中
  10. MPAndroidChart~BubbleChart(气泡图) and