Java: сопоставление фраз в строке - PullRequest
2 голосов
/ 17 мая 2011

У меня есть список фраз (фраза может состоять из одного или нескольких слов) в базе данных и строка ввода.Мне нужно выяснить, какие из этих фраз появляются во входной строке.

Существует ли эффективный способ выполнить такое сопоставление в Java?

Ответы [ 4 ]

3 голосов
/ 18 мая 2011

Быстрый взлом будет:

  1. Построить регулярное выражение на основе комбинированных фраз
  2. Создайте набор, в котором перечислены фразы, которые до сих пор не соответствовали
  3. Повторно запускайте find, пока все фразы не будут найдены или не будет достигнут конец ввода, удаляя совпадения из набора оставшихся фраз, чтобы найти

Таким образом, ввод проходит только один раз, независимо от того, сколько фраз вы указали. Если компилятор regexp генерирует эффективный сопоставитель для нескольких альтернатив, это должно обеспечить достойную производительность. Однако это во многом зависит от ваших фраз и входной строки, а также от качества механизма регулярных выражений Java.

Пример кода (протестирован, но не оптимизирован и не профилирован для производительности):

public static boolean hasAllPhrasesInInput(List<String> phrases, String input) {
    Set<String> phrasesToFind = new HashSet<String>();
    StringBuilder sb = new StringBuilder();
    for (String phrase : phrases) {
        if (sb.length() > 0) {
            sb.append('|');
        }
        sb.append(Pattern.quote(phrase));
        phrasesToFind.add(phrase.toLowerCase());
    }
    Pattern pattern = Pattern.compile(sb.toString(), Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher(input);
    while (matcher.find()) {
        phrasesToFind.remove(matcher.group().toLowerCase());
        if (phrasesToFind.isEmpty()) {
            return true;
        }
    }
    return false;
}

Некоторые предостережения:

  • Приведенный выше код будет сопоставлять фразы как подстроки слов. Если должны совпадать только полные слова, вам нужно добавить границы слов ("\ b") в сгенерированные регулярные выражения.
  • Код должен быть изменен, если некоторые фразы могут быть подстроки других фраз.
  • Если вам нужно сопоставить текст, отличный от ASCII, вы должны добавить параметр регулярного выражения Pattern.UNICODE_CASE и вызвать toLowerCase(Locale) вместо toLowerCase(), используя подходящий Locale.
0 голосов
/ 18 мая 2011
sql = "SELECT phrase " + 
  " FROM phrases " + 
  " WHERE phrase LIKE $1";     
PreparedStatement pstmt =  conn.prepareStatement (sql);
// probably repeated, if more than one input:
pstmt.setString (1, "%" + input + "%");
ResultSet rs = pstmt.executeQuery ();

Подготовленный оператор проверяется на соответствие базе данных и быстрее для повторного вызова, поэтому, если у вас есть более одного ввода, он все равно должен быть быстрым, выполненным в цикле.

Конечно, вы можете загрузить все свои фразы в оперативную память, на карту.Медленно при подготовке, это может быть быстрее, если у вас несколько вызовов, а не один вход.Но базы данных часто достаточно эффективны для поиска.

0 голосов
/ 18 мая 2011

Вы можете организовать поисковые фразы из вашей базы данных в дерево, основанное на общих началах.Чем вы можете анализировать свой строковый символ за символом, пытаясь сопоставить его с узлами этого дерева.

0 голосов
/ 17 мая 2011

Вот решение с использованием Java.Поскольку вы не указали ничего о используемых вами строках, я рассмотрю общий пример

Pattern p = Pattern.compile("cat");
        // Create a matcher with an input string
Matcher m = p.matcher("one cat," +" two cats in the yard");
boolean b = m.matches();  // Should return true

Надеюсь, что это поможет

Ссылка: http://java.sun.com/developer/technicalArticles/releases/1.4regex/

...