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

Спасибо. Я отредактировал вопрос, чтобы добавить транслитерацию, а также помог Google в нескольких хоромах. –

ответ

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 Class NSM [Non-Spacing Mark]).

+1

Если вы хотите просто ** сравнить ** две строки, а не хранить канонизированные версии, доступно более надежное решение; см. http://stackoverflow.com/questions/12889760/sort-list-of-strings-with-localization –

1

Одно очевидное усовершенствование для текущего кода: используйте Map<Character, Character>, что вы с предварительного заполнения ваших отображений.

А затем просто проверьте, имеет ли эта карта отображение; так; использовать это; в противном случае используйте оригинальный символ.

Как объясняет Андробин, существуют специальные карты, которые не полагаются на объекты, но работают с примитивными типами, например, trove. Таким образом, в зависимости от вашего решения и требований; вы могли бы изучить это.

+0

К счастью, есть карта # getOrDefault – Androbin

+0

Я рекомендую примитивную карту для эффективности – Androbin

+0

есть, например, FastUtil, HPPC, Koloboke и Trove – Androbin