从字符串中删除重音符号

44

在Android中有没有一种不使用java.text.Normalizer(据我所知)可以从String中删除任何重音的方法。例如,"éàù" 变成 "eau"。

如果可能的话,我想避免解析字符串以检查每个字符!


2
如果你使用的是API 9或更高版本,Android就拥有java.text.Normalizer - eldarerathis
2
可能是 https://dev59.com/oljUa4cB1Zd3GeqPOy6y 的重复问题。 - cyborg
1
如果你正在进行排序或匹配操作,请查看Collator;它比自己去除重音更好,除非你需要显示结果。 - erickson
5个回答

99
在Android中有`java.text.Normalizer`(在最新版本中)。您可以使用它。 编辑: 以下是如何使用`Normalizer`的参考代码:
string = Normalizer.normalize(string, Normalizer.Form.NFD);
string = string.replaceAll("[^\\p{ASCII}]", "");

(从下面的评论链接中复制)


2
我正在尝试使用API级别7进行编码,以便与旧设备兼容,但我认为它不存在。 - Johann
你能提供一个示例来调用Normalizer.normalize函数以去除字符串中的重音符号吗? - Mister Smith
@Johann 在 API-9 中添加了 http://developer.android.com/reference/java/text/Normalizer.html - shkschneider
2
@Guillaume,你好,我来自波兰,使用“Ł”无法正常工作:s - Piszu
1
好的,这确实从字符串中剥离了所有非拉丁字符,而不仅仅是重音符号。 - ntninja
2
"[^\p{ASCII}]" 将删除所有非 ASCII 字符。您可以使用 "[\\p{M}]" 正则表达式来仅删除分解后的重音符号。来源:从字符串中删除重音符号和变音符号 - Afilu

8
我已经根据我的需求调整了Rabi的解决方案,希望它能帮助到某些人:
private static Map<Character, Character> MAP_NORM;
public static String removeAccents(String value)
{
    if (MAP_NORM == null || MAP_NORM.size() == 0)
    {
        MAP_NORM = new HashMap<Character, Character>();
        MAP_NORM.put('À', 'A');
        MAP_NORM.put('Á', 'A');
        MAP_NORM.put('Â', 'A');
        MAP_NORM.put('Ã', 'A');
        MAP_NORM.put('Ä', 'A');
        MAP_NORM.put('È', 'E');
        MAP_NORM.put('É', 'E');
        MAP_NORM.put('Ê', 'E');
        MAP_NORM.put('Ë', 'E');
        MAP_NORM.put('Í', 'I');
        MAP_NORM.put('Ì', 'I');
        MAP_NORM.put('Î', 'I');
        MAP_NORM.put('Ï', 'I');
        MAP_NORM.put('Ù', 'U');
        MAP_NORM.put('Ú', 'U');
        MAP_NORM.put('Û', 'U');
        MAP_NORM.put('Ü', 'U');
        MAP_NORM.put('Ò', 'O');
        MAP_NORM.put('Ó', 'O');
        MAP_NORM.put('Ô', 'O');
        MAP_NORM.put('Õ', 'O');
        MAP_NORM.put('Ö', 'O');
        MAP_NORM.put('Ñ', 'N');
        MAP_NORM.put('Ç', 'C');
        MAP_NORM.put('ª', 'A');
        MAP_NORM.put('º', 'O');
        MAP_NORM.put('§', 'S');
        MAP_NORM.put('³', '3');
        MAP_NORM.put('²', '2');
        MAP_NORM.put('¹', '1');
        MAP_NORM.put('à', 'a');
        MAP_NORM.put('á', 'a');
        MAP_NORM.put('â', 'a');
        MAP_NORM.put('ã', 'a');
        MAP_NORM.put('ä', 'a');
        MAP_NORM.put('è', 'e');
        MAP_NORM.put('é', 'e');
        MAP_NORM.put('ê', 'e');
        MAP_NORM.put('ë', 'e');
        MAP_NORM.put('í', 'i');
        MAP_NORM.put('ì', 'i');
        MAP_NORM.put('î', 'i');
        MAP_NORM.put('ï', 'i');
        MAP_NORM.put('ù', 'u');
        MAP_NORM.put('ú', 'u');
        MAP_NORM.put('û', 'u');
        MAP_NORM.put('ü', 'u');
        MAP_NORM.put('ò', 'o');
        MAP_NORM.put('ó', 'o');
        MAP_NORM.put('ô', 'o');
        MAP_NORM.put('õ', 'o');
        MAP_NORM.put('ö', 'o');
        MAP_NORM.put('ñ', 'n');
        MAP_NORM.put('ç', 'c');
    }

    if (value == null) {
        return "";
    }

    StringBuilder sb = new StringBuilder(value);

    for(int i = 0; i < value.length(); i++) {
        Character c = MAP_NORM.get(sb.charAt(i));
        if(c != null) {
            sb.setCharAt(i, c.charValue());
        }
    }

    return sb.toString();

}

1
以下是波兰重音符号的更多转换:MAP_NORM.put('Ą' to 'A'); MAP_NORM.put('Ę' to 'E'); MAP_NORM.put('Ć' to 'C'); MAP_NORM.put('Ł' to 'L'); MAP_NORM.put('Ń' to 'N'); MAP_NORM.put('Ś' to 'S'); MAP_NORM.put('Ź' to 'Z'); MAP_NORM.put('Ż' to 'Z'); MAP_NORM.put('ą' to 'a'); MAP_NORM.put('ę' to 'e'); MAP_NORM.put('ç' to 'c'); MAP_NORM.put('ć' to 'c'); MAP_NORM.put('ł' to 'l'); MAP_NORM.put('ń' to 'n'); MAP_NORM.put('ś' to 's'); MAP_NORM.put('ź' to 'z'); MAP_NORM.put('ż' to 'z'); - Michael Osofsky

5
这可能不是最高效的解决方案,但它可以解决问题,并且适用于所有Android版本:
private static Map<Character, Character> MAP_NORM;
static { // Greek characters normalization
    MAP_NORM = new HashMap<Character, Character>();
    MAP_NORM.put('ά', 'α');
    MAP_NORM.put('έ', 'ε');
    MAP_NORM.put('ί', 'ι');
    MAP_NORM.put('ό', 'ο');
    MAP_NORM.put('ύ', 'υ');
    MAP_NORM.put('ή', 'η');
    MAP_NORM.put('ς', 'σ');
    MAP_NORM.put('ώ', 'ω');
    MAP_NORM.put('Ά', 'α');
    MAP_NORM.put('Έ', 'ε');
    MAP_NORM.put('Ί', 'ι');
    MAP_NORM.put('Ό', 'ο');
    MAP_NORM.put('Ύ', 'υ');
    MAP_NORM.put('Ή', 'η');
    MAP_NORM.put('Ώ', 'ω');
}

public static String removeAccents(String s) {
    if (s == null) {
        return null;
    }
    StringBuilder sb = new StringBuilder(s);

    for(int i = 0; i < s.length(); i++) {
        Character c = MAP_NORM.get(sb.charAt(i));
        if(c != null) {
            sb.setCharAt(i, c.charValue());
        }
    }

    return sb.toString();
}

3

虽然Guillaume的答案可以起到作用,但它会从字符串中剥离所有非ASCII字符。如果您希望保留这些字符,请尝试以下代码(其中string是要简化的字符串):

// Convert input string to decomposed Unicode (NFD) so that the
// diacritical marks used in many European scripts (such as the
// "C WITH CIRCUMFLEX" → ĉ) become separate characters.
// Also use compatibility decomposition (K) so that characters,
// that have the exact same meaning as one or more other
// characters (such as "㎏" → "kg" or "ヒ" → "ヒ"), match when
// comparing them.
string = Normalizer.normalize(string, Normalizer.Form.NFKD);

StringBuilder result = new StringBuilder();

int offset = 0, strLen = string.length();
while(offset < strLen) {
    int character = string.codePointAt(offset);
    offset += Character.charCount(character);

    // Only process characters that are not combining Unicode
    // characters. This way all the decomposed diacritical marks
    // (and some other not-that-important modifiers), that were
    // part of the original string or produced by the NFKD
    // normalizer above, disappear.
    switch(Character.getType(character)) {
        case Character.NON_SPACING_MARK:
        case Character.COMBINING_SPACING_MARK:
            // Some combining character found
        break;

        default:
            result.appendCodePoint(Character.toLowerCase(character));
    }
}

// Since we stripped all combining Unicode characters in the
// previous while-loop there should be no combining character
// remaining in the string and the composed and decomposed
// versions of the string should be equivalent. This also means
// we do not need to convert the string back to composed Unicode
// before returning it.
return result.toString();

当然可以。如果您想保留大写,请使用result.appendCodePoint(character); 而不是result.appendCodePoint(Character.toLowerCase(character)); 。;-) - ntninja

0

所有带重音的字符都在扩展ASCII字符编码集中,其十进制值大于127。因此,您可以枚举字符串中的所有字符,如果十进制字符代码值大于127,则将其映射回所需的等效字符。没有简单的方法将带重音的字符映射回非带重音的对应字符 - 您必须在内存中保留某种映射以将扩展的十进制代码映射回非带重音的字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接