2013-09-27 373 views
0

我使用下面的鏈接創建的角色的關鍵= Unicode值一個HashMap和值是實際的字符應該映射到 - https://github.com/lmjabreu/solr-conftemplate/blob/master/mapping-ISOLatin1Accent.txt如何使用hashmap從Java中的unicode字符串中刪除重音符號?

到目前爲止,我已經寫了下面的代碼從字符串

刪除口音
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); 
    } 
} 

預期的結果應該是「納帕」,但事實證明沒有轉換正在執行,這可能是導致偏差的原因,我無法找到一個。

+0

您是否嘗試過使用其他特殊字符的字符串,如「\ u00FF \ u00FD \ u0178」,看看HashMap中本身按預期工作? – IllusiveBrian

+0

您的'characterMappings'地圖實際上並沒有包含帶有口音的字符'p'。 –

+0

哈希映射本身正在工作,但不是西里爾字符:( – AnkitSablok

回答

5

不舒爾爲什麼要使用HashMap。但如果你只是想刪除變音符號也許這會有所幫助:

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

- >納帕

(如果你堅持使用HashMap中你應該仍然是一個看起來的「正規化」類,因爲它可以在另一個方向,太)

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

+1

偉大的解決方案:) – samjaf

+0

是的,謝謝。不是我的。添加了源代碼。 – Scheintod

+0

這種情況不適用於「brûlée」 – AnkitSablok

0

您遇到了一些Java最醜陋的「特徵」: 一個Unicode字符可能由一個字符(甚至是三字符)表示。

實際上,令牌的長度爲5個字符。 á是兩個字符的組合,只能表示爲一個字符串。

這就是爲什麼

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

將無法​​編譯。

Here是一個更多的解釋。

在我的謙虛oppinion字符串是Java中最差的類之一。特別是如果您使用「非標準」字符。

要解決你的問題,我會建議改變你的地圖Map<String,String>Map<String,Character>。通過這種方式,您可以映射您的'字符',並且作爲一個整潔的副作用,如果您解散了轉義的Unicode字符,則您的代碼變得更具可讀性。

欲瞭解更多信息穀歌HighSurrogate或CodePoint。 CodePoints是有效的(=可顯示)char-sequences,如前所述 - 不需要與字符串中的字符數量相對應。

這是必要的,因爲Java字符只有2個字節寬。對於所有的unicode字符小,但大到足夠大部分時間(=只要你使用標準的拉丁字符)。

編輯:

即使有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值​​得信任。來源發現here

問候

SAM

+0

好吧,如果它不匹配散列表中的字符它會匹配字符串嗎? – AnkitSablok

+0

你提供的代碼片段對我來說不起作用 – AnkitSablok

+0

請注意,stackoverflow代碼段並不能很好地處理重音符號,請熟練掌握你的案例。 e口音超過「a」,而不是p。 「put」語句在答案中也是不合格的。 – samjaf

相關問題