2017-02-22 57 views
0

我正在研究必須爲某些句子編制索引的應用程序。目前使用Java和PostgreSQL。這些句子可以使用幾種語言,如法語和西班牙語,使用重音符號和其他非ASCII符號。如何將字符串縮減爲ASCII 7字符以進行索引?

對於每個單詞我想創建一個索引相當的等價物,以便用戶可以對重音(音譯)執行不敏感的搜索。例如,當用戶搜索「nacion」時,即使應用程序存儲的原始單詞是「Naci -n」,它也必須找到它。

什麼可能是最好的策略?我不一定僅限於PostgreSQL,也不一定要求內部索引值與原始單詞有任何相似性。理想情況下,它應該是將任何Unicode字符串轉換爲不區分大小寫和重音符號的ASCII字符串的通用解決方案。

到目前爲止,我正在使用下面顯示的自定義函數,它在存儲索引值之前只會用ASCII等價物替換一些字母,並在查詢字符串上執行相同的操作。

public String toIndexableASCII (String sStrIn) { 
    if (sStrIn==null) return null; 
    int iLen = sStrIn.length(); 
    if (iLen==0) return sStrIn; 
    StringBuilder sStrBuff = new StringBuilder(iLen); 
    String sStr = sStrIn.toUpperCase(); 

    for (int c=0; c<iLen; c++) { 
    switch (sStr.charAt(c)) { 
     case 'Á': 
     case 'À': 
     case 'Ä': 
     case 'Â': 
     case 'Å': 
     case 'Ã': 
     sStrBuff.append('A'); 
     break; 
     case 'É': 
     case 'È': 
     case 'Ë': 
     case 'Ê': 
     sStrBuff.append('E'); 
     break; 
     case 'Í': 
     case 'Ì': 
     case 'Ï': 
     case 'Î': 
     sStrBuff.append('I'); 
     break; 
     case 'Ó': 
     case 'Ò': 
     case 'Ö': 
     case 'Ô': 
     case 'Ø': 
     sStrBuff.append('O'); 
     break; 
     case 'Ú': 
     case 'Ù': 
     case 'Ü': 
     case 'Û': 
     sStrBuff.append('U'); 
     break; 
     case 'Æ': 
     sStrBuff.append('E'); 
     break; 
     case 'Ñ': 
     sStrBuff.append('N'); 
     break; 
     case 'Ç': 
     sStrBuff.append('C'); 
     break; 
     case 'ß': 
     sStrBuff.append('B'); 
     break; 
     case (char)255: 
     sStrBuff.append('_'); 
     break; 
     default: 
     sStrBuff.append(sStr.charAt(c)); 
    } 
    } 

    return sStrBuff.toString(); 
} 
+0

將字節解釋爲ASCII 7不會提供我想實現的「信息丟失」。我希望「coraçón」與「coracon」相同,以便用戶在搜索時是否放入重音符號並不重要。我不需要像Google這樣的拼寫檢查或接近檢查程序「你的意思是...?」但我確實需要「é」==「e」。 –

+1

你問的地圖叫做「音譯」。 –

+0

謝謝。我編輯了這個問題以添加音譯,也幫助我向谷歌提供了一些優秀的匹配。 –

回答

2
String s = "Nación"; 

    String x = Normalizer.normalize(s, Normalizer.Form.NFD); 

    StringBuilder sb=new StringBuilder(s.length()); 
    for (char c : x.toCharArray()) { 
     if (Character.getType(c) != Character.NON_SPACING_MARK) { 
      sb.append(c); 
     } 
    } 

    System.out.println(s); // Nación 
    System.out.println(sb.toString()); // Nacion 

這是如何工作: 據國際字符分割高達NFD分解(ó變得o◌́),然後剝離組合語音標記。

Character.NON_SPACING_MARK包含組合變音符號(Unicode稱之爲Bidi類NSM [Non-Spacing Mark])。

+1

如果你只想**比較**兩個字符串,而不是存儲規範化版本,更強大的解決方案可用;請參閱http://stackoverflow.com/questions/12889760/sort-list-of-strings-with-localization –

1

您當前的代碼的一個明顯的改進:採用Map<Character, Character>,你充液與您的映射。

然後只要檢查該Map是否有映射;如此;使用它;否則使用原始字符。

Androbin解釋說,有些特殊的地圖不依賴於對象,而是使用原始類型,如trove。所以,取決於你的解決方案和要求;你可以看看。

+0

幸運的是,有地圖#getOrDefault – Androbin

+0

我推薦一個原始地圖效率爲 – Androbin

+0

有例如FastUtil,HPPC,Koloboke和Trove – Androbin

相關問題