如何将字符串缩减为 ASCII 7 个字符以用于索引目的?
How to reduce a string to ASCII 7 characters for indexing purposes?
我正在开发一个必须为某些句子编制索引的应用程序。目前使用 Java 和 PostgreSQL。这些句子可能使用多种语言,如法语和西班牙语,使用重音符号和其他非 ASCII 符号。
我想为每个单词创建一个可索引的等效词,以便用户可以执行对重音(音译)不敏感的搜索。例如,当用户搜索 "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();
}
您当前代码的一项明显改进:使用您 预填充 映射的 Map<Character, Character>
。
然后简单地检查那个Map是否有映射;所以;使用那个;否则使用原始字符。
正如 Androbin 所解释的那样,有一些特殊的映射不依赖于对象,而是使用原始类型,就像这样 trove。因此,取决于您的解决方案和要求;你可以看看那个。
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 Class NSM [Non-Spacing Mark])。
我正在开发一个必须为某些句子编制索引的应用程序。目前使用 Java 和 PostgreSQL。这些句子可能使用多种语言,如法语和西班牙语,使用重音符号和其他非 ASCII 符号。
我想为每个单词创建一个可索引的等效词,以便用户可以执行对重音(音译)不敏感的搜索。例如,当用户搜索 "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();
}
您当前代码的一项明显改进:使用您 预填充 映射的 Map<Character, Character>
。
然后简单地检查那个Map是否有映射;所以;使用那个;否则使用原始字符。
正如 Androbin 所解释的那样,有一些特殊的映射不依赖于对象,而是使用原始类型,就像这样 trove。因此,取决于您的解决方案和要求;你可以看看那个。
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 Class NSM [Non-Spacing Mark])。