Поиск строк из массива в строке

283
30 марта 2017, 19:41

Есть строка:

String text = " I hate spam."

Также есть массив строк:

String[] keywords = new String[] { "spam", "spamer" };

Необходимо проверить, имеется ли в text такой же "spam" как и в keywords.

В каком направлении двигаться для решения задачи?

Answer 1

Предположим, что нужно проверять, содержится ли хотя бы одно ключевое слово (стоп-слово) в заданной строке.

Полный перебор ключевых слов с проверкой с помощью метода contains

private static boolean bruteForce(String text, String[] keywords)
{
    for (String keyword : keywords)
    {
        if (text.contains(keyword))
        {
            return true;
        }
    }
    return false;
}

прост в реализации и быстро работает при небольшой длине строки и небольшом количестве ключевых строк.

Однако при большом объёме данных этот алгоритм начинает работать достаточно долго.
При длине строки в миллион символов и 10 тысячах ключевых слов (длина каждого - 20 символов) у меня алгоритм работает 3100-3200мс при условии, что в строке есть только последнее ключевое слово в конце строки.

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

Представленный ниже алгоритм отличается от алгоритма Ахо - Корасик в плане обработки несовпадения подстроки, однако работает всё равно достаточно быстро (на тех же данных - 60-70мс).

При проверке множества строк на одни и те же ключевые слова имеет смысл построить ДКА один раз и в дальнейшем использовать его для всех строк. В таком случае время обработки для исходной строки снизится до 40-50мс.

Класс состояния ДКА с учетом оптимизации:

private static class State
{
    private Map<Character, State> transitions;
    public boolean isFinal = false;
    private char firstChar;
    private State firstState = null;
    public State get(char c)
    {
        if (firstState != null && firstChar == c)
        {
            return firstState;
        }
        if (transitions != null)
        {
            return transitions.get(c);
        }
        return null;
    }
    public State getOrCreate(char c)
    {
        if (firstState != null && firstChar == c)
        {
            return firstState;
        }
        if (firstState == null)
        {
            firstState = new State();
            firstChar = c;
            return firstState;
        }
        if (transitions == null)
        {
            transitions = new HashMap<>();
        }
        State state = transitions.get(c);
        if (state == null)
        {
            state = new State();
            transitions.put(c, state);
        }
        return state;
    }
}

Формирование ДКА и поиск по строке:

private static boolean dfa(String text, String[] keywords)
{
    State root = new State();
    for (String keyword : keywords)
    {
        State state = root;
        for (char c : keyword.toCharArray())
        {
            state = state.getOrCreate(c);
        }
        state.isFinal = true;
    }
    State state = root;
    int foundSymbols = 0;
    for (int i = 0; i < text.length(); i++)
    {
        state = state.get(text.charAt(i));
        if (state == null)
        {
            i -= foundSymbols;
            state = root;
            foundSymbols = 0;
        }
        else if (state.isFinal)
        {
            return true;
        }
        else
        {
            foundSymbols++;
        }
    }
    return false;
}
Answer 2

Нашел способ! :)

text.contains(String.valueOf(keywords[0]));

ну а keywords, соответственно в цикл для перебора по индексу

Answer 3

Можно попробовать так:

String text = " I hate spam.";
String[] keywords = new String[] {"spam", "spamer"};
boolean isContains = false;
for (String s : keywords) {
   if (text.contains(s)) {
      isContains = true;
      break;
   }
}
if (isContains) {
   // слово содержится...
}
READ ALSO
Java renameTo - не работает переименование

Java renameTo - не работает переименование

Добрый деньНикак не могу понять как переименовывать файл в Java, т

351
Можно ли обойти ограничение на запись на ExSDcard?

Можно ли обойти ограничение на запись на ExSDcard?

Пишу простую программу для шифрования данных в AndroidСтолкнулся с такой проблемой, что нет доступа на запись к exSDcard устройств

263
Открытие Jar через winrar

Открытие Jar через winrar

Заинтерисовал меня такой вопрос, возможно ли сделать так, что бы jar нельзя было бы открыть с помощью winrarПытался завернуть в exe с помощью launch4j,...

268