Indexing 如何将字符串缩减为ASCII 7个字符以用于索引目的?

Indexing 如何将字符串缩减为ASCII 7个字符以用于索引目的?,indexing,ascii,non-ascii-characters,transliteration,Indexing,Ascii,Non Ascii Characters,Transliteration,我正在做一个应用程序,它必须索引某些句子。目前正在使用Java和PostgreSQL。这些句子可能使用几种语言,如法语和西班牙语,使用重音和其他非ASCII符号 对于每个单词,我想创建一个可索引的等价词,以便用户可以执行对重音不敏感的搜索(音译)。例如,当用户搜索“nacion”时,即使应用程序存储的原始单词是“Nacion”,也必须找到它 这方面的最佳策略是什么?我不一定只限于PostgreSQL,内部索引值也不需要与原始单词有任何相似性。理想情况下,它应该是将任何Unicode字符串转换为对

我正在做一个应用程序,它必须索引某些句子。目前正在使用Java和PostgreSQL。这些句子可能使用几种语言,如法语和西班牙语,使用重音和其他非ASCII符号

对于每个单词,我想创建一个可索引的等价词,以便用户可以执行对重音不敏感的搜索(音译)。例如,当用户搜索“nacion”时,即使应用程序存储的原始单词是“Nacion”,也必须找到它

这方面的最佳策略是什么?我不一定只限于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();
}
public字符串到indexableascii(字符串sStrIn){
if(sStrIn==null)返回null;
int-iLen=sStrIn.length();
如果(iLen==0)返回sStrIn;
StringBuilder sStrBuff=新的StringBuilder(iLen);
字符串sStr=sStrIn.toUpperCase();

对于(int c=0;c当前代码的一个明显改进:使用
Map
对映射进行预填充

然后简单地检查该映射是否有映射;当然,使用该映射;否则使用原始字符


正如Androbin所解释的,有一些特殊的映射不依赖于对象,而是与基本类型一起工作,如下图所示。因此,根据您的解决方案和要求,您可以对此进行研究。

当前代码的一个明显改进是:使用一个
映射,在映射中预先填充

    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
然后简单地检查该映射是否有映射;当然,使用该映射;否则使用原始字符

正如Androbin所解释的,有一些特殊的映射不依赖于对象,而是与基本类型一起工作,就像这样

    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
工作原理: 它将国际字符拆分为分解(
o
变成
o)◌́
),然后去除组合变音符号

字符。非间隔标记
包含组合变音符号(Unicode称之为Bidi类)

工作原理: 它将国际字符拆分为分解(
o
变成
o)◌́
),然后去除组合变音符号


字符。非间隔标记
包含组合变音符号(Unicode称之为Bidi类)。

将字节解释为ASCII 7不会提供我想要实现的“信息丢失”。我希望“coraçón”与“coracon”相同因此,用户在搜索时是否输入重音并不重要。我不需要像谷歌那样的拼写或接近度检查器“你的意思是…?”但我需要“é”=“e”。你询问的映射称为“音译”谢谢。我编辑了这个问题以添加音译,还帮我搜索了一些好匹配。将字节解释为ASCII 7不会提供我想要实现的“信息丢失”。我希望“coraçón”与“coracon”相同因此,用户在搜索时是否输入重音并不重要。我不需要像谷歌那样的拼写或接近度检查器“你的意思是…?”但我需要“é”=“e”。你询问的映射称为“音译”谢谢。我编辑了这个问题以添加音译,还帮助我搜索了一些好的匹配项。谢天谢地,有Map#getOrDefaultI推荐一个原始地图以提高效率有例如FastUtil、HPPC、Koloboke和TroveThankly,有Map#getOrDefaultI推荐一个原始地图以提高效率有例如FastUtil、HPPC、,Koloboke和Trovei如果您只想比较两个字符串,而不是存储规范化版本,则可以使用更健壮的解决方案;如果您只想比较两个字符串,而不是存储规范化版本,则可以使用更健壮的解决方案;请参阅