Поиск подходящих выражений как это сделано в IDEA

86
08 июня 2021, 12:20

Есть набор предложений по типу "Green Apple", и каждое имеет от 2 до 7 слов. Нужно находить среди них к примеру "Green Apple" по таким ключевым словам как "gra" или "gap". Как это можно сделать?

Answer 1

Мне кажется, тут оптимальней использовать Trie. Например, есть класс

public class TrieNode {
    private HashMap<Character, TrieNode> _children = new HashMap<>();
    private String _payload = null;
}

Он хранит текущее слово и подузлы, где каждый подузел асоциирован с символом. Далее, напишем для класса функцию добавления слова

public void add(String str) {
    add(str, 0);
}
private void add(String str, int ind) {
    if (str.length() == ind) {
        _payload = str;
        return;
    }
    Character c = str.charAt(ind);
    c = Character.toLowerCase(c);
    if (_children.containsKey(c)) _children.get(c).add(str, ind + 1);
    else {
        TrieNode next = new TrieNode();
        _children.put(c, next);
        next.add(str, ind + 1);
    }
}

Функцию поиска по паттерну

public ArrayList<String> retrieve(String filter) {
    ArrayList<String> result = new ArrayList<>();
    retrieve(filter.toLowerCase(), 0, result);
    return result;
}
private void retrieve(String filter, int index, ArrayList<String> result) {
    if (index < filter.length()) {
        Character current = filter.charAt(index);
        for (Character c : _children.keySet()) {
            if (c.equals(current)) _children.get(c).retrieve(filter, index + 1, result);
            else _children.get(c).retrieve(filter, index, result);
        }
    }
    if (index >= filter.length()) {
        if (_payload != null) result.add(_payload);
        for (TrieNode n : _children.values()) n.retrieve(filter, index, result);
    }
}

Как это все тестировать

public static void main(String[] args) {
    TrieNode root = new TrieNode();
    root.add("Green Apple");
    root.add("Bla bla bla");
    root.add("StackOverflow");
    ShowSearchResultFor(root, "gra");
    ShowSearchResultFor(root, "gap");
    ShowSearchResultFor(root, "sof");
    ShowSearchResultFor(root, "bbb");
    ShowSearchResultFor(root, "a");
}
private static void ShowSearchResultFor(TrieNode root, String filter){
    System.out.println();
    System.out.println("results for: " + filter);
    for(String ret : root.retrieve(filter)){
        System.out.println(ret);
    }
}

Вывод в консоль ожидаем

results for: gra
Green Apple
results for: gap
Green Apple
results for: sof
StackOverflow
results for: bbb
Bla bla bla
results for: a
Bla bla bla
StackOverflow
Green Apple
Answer 2

Более лаконичный, но вероятно (не проверял) более медленнный подход

private static void ShowSearchResultFor(String[] words, String filter){
    filter = filter.toLowerCase();
    System.out.println();
    System.out.println("results for: " + filter);
    for(String w : words){
        int ind = 0;
        for(Character cw : w.toLowerCase().toCharArray()){
            if (cw.equals(filter.charAt(ind))) ind++;
            if (ind >= filter.length()){
                System.out.println(w);
                break;
            }
        }
    }
}

как проверить

public static void main(String[] args) {
    String[] words = new String[3];
    words[0] = "Green Apple";
    words[1] = "Bla bla bla";
    words[2] = "StackOverflow";
    ShowSearchResultFor(words, "gra");
    ShowSearchResultFor(words, "gap");
    ShowSearchResultFor(words, "sof");
    ShowSearchResultFor(words, "bbb");
    ShowSearchResultFor(words, "a");
    ShowSearchResultFor(words, "StackOverflow");
}

Вывод

results for: gra
Green Apple
results for: gap
Green Apple
results for: sof
StackOverflow
results for: bbb
Bla bla bla
results for: a
Green Apple
Bla bla bla
StackOverflow
results for: stackoverflow
StackOverflow
Answer 3

Вангую, что самый медленный способ с регулярками

private static void ShowSearchResultFor(String[] words, String filter){
    filter = filter.toLowerCase();
    System.out.println();
    System.out.println("results for: " + filter);
    StringBuffer buffer = new StringBuffer();
    for(Character c : filter.toCharArray()){
        buffer.append(c);
        buffer.append(".*");
    }
    Pattern p = Pattern.compile(buffer.toString());
    for(String w : words){
        Matcher m = p.matcher(w.toLowerCase());
        if (m.find()) System.out.println(w);
    }
}

Как проверить

public static void main(String[] args) {
    String[] words = new String[3];
    words[0] = "Green Apple";
    words[1] = "Bla bla bla";
    words[2] = "StackOverflow";
    ShowSearchResultFor(words, "gra");
    ShowSearchResultFor(words, "gap");
    ShowSearchResultFor(words, "sof");
    ShowSearchResultFor(words, "bbb");
    ShowSearchResultFor(words, "a");
    ShowSearchResultFor(words, "StackOverflow");
}

Вывод

results for: gra
Green Apple
results for: gap
Green Apple
results for: sof
StackOverflow
results for: bbb
Bla bla bla
results for: a
Green Apple
Bla bla bla
StackOverflow
results for: stackoverflow
StackOverflow
READ ALSO
Обработка нескольких слушателей

Обработка нескольких слушателей

У меня есть два поля EditText и 4 кнопки

81
Прикрутить git к processbuilder

Прикрутить git к processbuilder

решил поработать с командной строкой в javaНашел способ работы с cmd через ProcessBuilder

115
Как указать обработчику кнопки внутри ListView выйти из текущего Activity?

Как указать обработчику кнопки внутри ListView выйти из текущего Activity?

Есть кастомный ListView, каждый Item содержит Button

115