2017-02-22 63 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

相关问题