Java - Язык:Поиск по ключам HashMap на основе регулярного выражения?

StackOverflow https://stackoverflow.com/questions/879807

  •  22-08-2019
  •  | 
  •  

Вопрос

Я создаю тезаурус, используя HashMap для хранения синонимов.

Я пытаюсь выполнить поиск по словам на основе регулярного выражения:метод должен будет принять строку в качестве параметра и вернуть массив результатов.Вот мой первый взгляд на это:

public ArrayList<String> searchDefinition(String regex) {
    ArrayList<String> results = new ArrayList<String>();

    Pattern p = Pattern.compile(regex);

    Set<String> keys = thesaurus.keySet();
    Iterator<String> ite = keys.iterator();

    while (ite.hasNext()) {
        String candidate = ite.next();
        Matcher m = p.matcher(candidate);
        System.out.println("Attempting to match: " + candidate + " to "  + regex);
        if (m.matches()) {
            System.out.println("it matches");
            results.add(candidate);
        }
    }   

    if (results.isEmpty()) {
        return null;
    }
    else {
        return results;
    }
}

Теперь это работает не так, как я ожидал бы (или, возможно, я неправильно использую регулярные выражения).Если у меня есть следующие ключи в hashmap:

cat, car, chopper

затем, позвонив searchDefinition("c") или searchDefinition("c*") Я получаю null.

  1. Как мне заставить это работать так, как ожидалось?
  2. Существует ли лучшая структура данных, чем HashMap, для сохранения graph как это необходимо для тезауруса?(только из любопытства, так как для этого задания нас просят использовать Java Collection Map).
  3. Что-нибудь еще, что я делаю неуместно в приведенном выше коде?

Спасибо, Дэн

Редактировать:Я исправил этот пример.Это не сработает, даже если я использую правильный регистр.

Это было полезно?

Решение

Вам нужно указать нечувствительность к регистру Шаблон.скомпилировать( "c",Шаблон.НЕЧУВСТВИТЕЛЬНЫЙ К СЛУЧАЮ ).Чтобы найти слово с c в нем вам нужно использовать совпадающий.find(). Сопоставитель.совпадения() пытается сопоставить всю строку целиком.

Другие советы

Но, хм:

(a) Зачем вам использовать HashMap, если вы намерены всегда выполнять поиск по нему последовательно?Это много потраченных впустую накладных расходов на обработку хэш-ключей и всего остального, когда вы никогда ими не пользуетесь.Конечно, простой ArrayList или LinkedList был бы лучшей идеей.

(b) Какое это имеет отношение к тезаурусу?Зачем вам искать в тезаурусе, используя регулярные выражения?Если бы я хотел знать синонимы, скажем, для "кошки", я бы подумал, что я бы искал "cat", а не "c. *".

Моей первой мыслью о том , как создать тезаурус , было бы ...ну, я думаю, первый вопрос, который я бы задал, это: "Является ли синоним отношением эквивалентности?", т. е.если A является синонимом B, следует ли из этого, что B является синонимом A?И если A - синоним B, а B - синоним C, то является ли A синонимом C?Предполагая, что ответы на эти вопросы "да", тогда мы хотим создать нечто, разделяющее все слова в языке на наборы синонимов, чтобы затем мы могли сопоставить любое слово в каждом наборе со всеми остальными словами в этом наборе.Итак, что вам нужно, так это способ взять любое слово, сопоставить его с какой-то точкой связи, а затем перейти от этой точки связи ко всем словам, которые сопоставляются с ним.

Это было бы просто в базе данных:Просто создайте таблицу с двумя столбцами, скажем "word" и "token", каждый со своим собственным индексом.Все синонимы соответствуют одному и тому же токену.Токен может быть любым, главное, чтобы он был уникальным для любого заданного набора синонимов, например порядковый номер.Затем выполните поиск по заданному слову, найдите связанный с ним токен, а затем получите все слова с этим токеном.Например, мы могли бы создавать записи с (big,1), (large,1), (gigantic,1), (cat, 2), (feline, 2) и т.д.Найдите "большой" и получите 1, затем найдите 1 и получите "большой", "large" и "giant".

Я не знаю ни одного класса во встроенных коллекциях Java, который делал бы это.Самый простой способ, который я могу придумать, - это создать две скоординированные хэш-таблицы:Один, который сопоставляет слова с токенами, а другой, который сопоставляет токены с массивом слов.Таким образом, таблица 1 может содержать big->1, large->1, gigantic->1, cat->2, feline->2 и т.д.Затем таблица 2 отображает карты 1-> [большой, large, gigantic], 2->[cat, кошачий] и т.д.Вы просматриваете первую таблицу, чтобы сопоставить слово с символом, а во второй - чтобы сопоставить этот символ обратно со списком слов.Это неуклюже, потому что все данные хранятся с избытком, возможно, есть лучшее решение, но я не берусь за него сразу.(Ну, это было бы легко, если бы мы предположили, что будем каждый раз последовательно выполнять поиск по всему списку слов, но производительность снизилась бы, поскольку список стал большим.)

Это то регулярное выражение, которое вы используете?

Метод Matcher.matches() возвращает true только в том случае, если вся последовательность ввода соответствует выражению (из Javadoc), поэтому вам нужно будет использовать "c.*" в данном случае, не "c*" а также сопоставление без учета регистра.

Регулярные выражения чувствительны к регистру.Ты хочешь:

Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);

Похоже, вы используете свои регулярные выражения ненадлежащим образом."c" будет соответствовать только строчному c, а не заглавному регистру.

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

Отвечая на фразу Джея "Но хм" выше,

(Я бы добавил комментарий, но у меня нет представителя.)

Поиск по нему последовательно выполняется медленным способом.Делать это с помощью регулярных выражений - значит впадать в безумие.Выполнение этого с помощью базы данных - это выход из положения при программировании.Конечно, если бы ваш набор данных был огромным, это могло бы потребоваться, но помните, что "для этого назначения нас просят использовать Java Collection Map", мы должны выяснить, как правильно использовать эту Java collection.

Причина, по которой это не очевидно, заключается в том, что это не одна коллекция.Это два.Но это не две карты.Это не ArrayList.Чего не хватает, так это Набора.Это сопоставление с наборами синонимов.

Set<String> позволит вам создавать свои списки синонимов.Вы можете приготовить столько, сколько захотите.Хорошим примером могли бы стать два набора синонимов.Это набор, а не ArrayList, потому что вам не нужны повторяющиеся слова.

Карта<String, Set<String="">> позволит вам быстро сориентироваться от любого слова к набору его синонимов.

Создавайте свои декорации.Затем постройте карту.Напишите вспомогательный метод для построения карты, который использует карту и набор.

addSet(Карта<String, Set<String="">> карта, установить<String> Новый набор)

Этот метод просто зацикливает newSet и добавляет строки на карту в качестве ключей и ссылку на newSet в качестве значения.Вы бы вызвали addSet один раз для каждого набора.

Теперь, когда ваша структура данных построена, мы должны быть в состоянии находить материал.Чтобы сделать это немного надежнее, не забудьте очистить свой поисковый ключ перед началом поиска.Используйте trim(), чтобы избавиться от бессмысленных пробелов.Используйте toLowerCase(), чтобы избавиться от бессмысленной заглавной буквы.Вы должны были выполнить оба этих действия с данными синонимов до (или во время) создания наборов.Сделайте это, и кому для этого нужны регулярные выражения?Этот способ намного быстрее и, что более важно, безопаснее.Регулярные выражения очень эффективны, но могут стать настоящим кошмаром при отладке, когда они идут не так, как надо.Не используйте их только потому, что вы считаете их крутыми.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top