1

我正在使用以下链接创建 key = unicode 字符值的哈希图,值是它应该映射到的实际字符 - https://github.com/lmjabreu/solr-conftemplate/blob/master/mapping-ISOLatin1Accent。文本

到目前为止,我已经编写了以下代码来从字符串中删除重音符号

public class ACCENTS {

    public static void main(String[] args){

        // this is the hashmap that stores the mappings of the characters to their ascii equivalent
        HashMap<Character, Character> characterMappings = new HashMap<>();

        characterMappings.put('\u00C0', 'A');
        characterMappings.put('\u00C1', 'A');
        characterMappings.put('\u00C2', 'A');
        characterMappings.put('\u00C3', 'A');
        characterMappings.put('\u00C4', 'A');
        characterMappings.put('\u00C5', 'A');
        characterMappings.put('\u00C7','C');
        characterMappings.put('\u00C8', 'E');
        characterMappings.put('\u00C9','E');
        characterMappings.put('\u00CA', 'E');
        characterMappings.put('\u00CB', 'E');
        characterMappings.put('\u00CC', 'I');
        characterMappings.put('\u00CD', 'I');
        characterMappings.put('\u00CE', 'I');
        characterMappings.put('\u00CF', 'I');
        characterMappings.put('\u00D0', 'D');
        characterMappings.put('\u00D1', 'N');
        characterMappings.put('\u00D2', 'O');
        characterMappings.put('\u00D3', 'O');
        characterMappings.put('\u00D4', 'O');
        characterMappings.put('\u00D5', 'O');
        characterMappings.put('\u00D6', 'O');
        characterMappings.put('\u00D8', 'O');
        characterMappings.put('\u00D9', 'U');
        characterMappings.put('\u00DA', 'U');
        characterMappings.put('\u00DB', 'U');
        characterMappings.put('\u00DC', 'U');
        characterMappings.put('\u00DD', 'Y');
        characterMappings.put('\u0178', 'Y');
        characterMappings.put('\u00E0', 'a');
        characterMappings.put('\u00E1', 'a');
        characterMappings.put('\u00E2', 'a');
        characterMappings.put('\u00E3','a');
        characterMappings.put('\u00E4', 'a');
        characterMappings.put('\u00E5', 'a');
        characterMappings.put('\u00E7', 'c');
        characterMappings.put('\u00E8', 'e');
        characterMappings.put('\u00E9', 'e');
        characterMappings.put('\u00EA','e');
        characterMappings.put('\u00EB', 'e');
        characterMappings.put('\u00EC', 'i');
        characterMappings.put('\u00ED', 'i');
        characterMappings.put('\u00EE', 'i');
        characterMappings.put('\u00EF', 'i');
        characterMappings.put('\u00F0', 'd');
        characterMappings.put('\u00F1','n' );
        characterMappings.put('\u00F2', 'o');
        characterMappings.put('\u00F3', 'o');
        characterMappings.put('\u00F4', 'o');
        characterMappings.put('\u00F5', 'o');
        characterMappings.put('\u00F6', 'o');
        characterMappings.put('\u00F8', 'o');
        characterMappings.put('\u00F9', 'u');
        characterMappings.put('\u00FA', 'u');
        characterMappings.put('\u00FB', 'u');
        characterMappings.put('\u00FC', 'u');
        characterMappings.put('\u00FD', 'y');
        characterMappings.put('\u00FF', 'y');

        String token = "nа̀ра";
        String newString = "";


        for(int i = 0 ; i < token.length() ; ++i){
            if( characterMappings.containsKey(token.charAt(i)) )
                newString += characterMappings.get(token.charAt(i));
            else
                newString += token.charAt(i);
        }

        System.out.println(newString);
    }
}

预期的结果应该是“napa”,但事实证明没有执行任何转换,这可能是导致这种情况下偏差的可能原因,我找不到。

4

2 回答 2

5

不确定为什么要使用 HashMap。但是,如果您只想删除变音符号,这可能会有所帮助:

String s = "nа̀ра";
s = Normalizer.normalize( s, Normalizer.Form.NFD );
s = s.replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
System.out.println( s );

--> 纳帕

(如果你坚持使用 HashMap,你应该仍然看一下“Normalizer”类,因为它也可以在另一个方向上工作。)

摘自这篇文章:http: //blog.smartkey.co.uk/2009/10/how-to-strip-accents-from-strings-using-java-6/

于 2013-09-27T17:34:27.047 回答
1

您遇到了 Java 的一些最丑陋的“特性”:一个 unicode 字符可能由一个元组(甚至一个三元组)字符表示。

实际上,token 的长度为 5 个字符。á 是两个字符的组合,只能表示为字符串。

这就是为什么

 characterMappings.put('а̀`', 'y'); //(accent can't be displayed correctly in code-mode, try it yourself)

不会编译。

是一个更多的解释。

在我看来,String 是 Java 中最糟糕的类之一。特别是如果您使用“非标准”字符。

为了解决您的问题,我建议将您的地图更改为Map<String,String>or Map<String,Character>。通过这种方式,您可以映射您的“字符”,并且作为一个简洁的副作用,如果您忽略转义的 unicode 字符,您的代码将变得更具可读性。

有关 HighSurrogate 或 CodePoint 的更多信息,请访问谷歌。CodePoints 是有效的(=可显示的)字符序列,如前所述,它们不一定与字符串中的字符数相对应。

这是必要的,因为 Java 字符只有 2 个字节宽。对于所有 unicode 字符来说要小,但大多数时候足够大(=只要您使用标准拉丁字符)。

编辑:

即使使用 a Map<String,String>,您的代码也无法工作,因为您仍然会遍历字符。但是没有一个 Java 字符会匹配你特殊的 unicode 字符。

这可能会有所帮助,尽管它可能在任何情况下都不起作用(毕竟 java 字符串很讨厌):

HashMap<String, String> characterMappings = new HashMap<>();
characterMappings.put("а̀", "a");

String token = "nа̀ра";
String newString = "";

for (Entry<String, String> e : characterMappings.entrySet()) {
    token = token.replaceAll(e.getKey(), e.getValue());
}
System.out.println(token);

编辑 2

由于将代码作为评论发布很糟糕:

    String s = "brûlée";
    String s1 = Normalizer.normalize(s, Normalizer.Form.NFKD);
    String regex = "[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+";

    String s2 = new String(s1.replaceAll(regex, "").getBytes("ascii"),
            "ascii");

    System.out.println(s2);

这对我到目前为止所尝试的一切都有效。仍然@Scheintod 值得称赞。来源在这里

此致

山姆

于 2013-09-27T17:07:00.373 回答