2013-09-19 2 views
10

Привет, товарищи! Я пытаюсь создать программу, которая обнаруживает, что несколько слов в строке как можно быстрее, и если это так, выполняет поведение. Предпочтительно, я хотел бы, чтобы он также определял порядок этих слов, но только если это можно сделать быстро. До сих пор это то, что я сделал:Лучший способ определить, содержит ли строка несколько слов

if (input.contains("adsf") && input.contains("qwer")) { 
    execute();   
} 

Как вы можете видеть, выполнение этого для нескольких слов стало бы утомительным. Это единственный способ или лучший способ обнаружения множества подстрок? И есть ли способ обнаружения порядка?

ответ

9

Вы можете использовать массив:

String[] matches = new String[] {"adsf", "qwer"}; 

bool found = false; 
for (String s : matches) 
{ 
    if (input.contains(s)) 
    { 
    execute(); 
    break; 
    } 
} 

Это является эффективным, как один публикуемую Вами, но более ремонтопригодны. Поиск более эффективного решения звучит как микро-оптимизация, которую следует игнорировать до тех пор, пока это не станет эффективным узким местом вашего кода, в любом случае с огромным набором строк решение может быть trie.

+0

Хм, я считаю, что это должно хорошо работать для моего небольшого проекта. Спасибо за такой быстрый ответ! – Silver

+4

Действительно ли это работает так же, как и код? Это должно работать больше как оператор или оператор. – aycanadal

+0

для больших наборов слов для соответствия одному варианту алгоритм aho-corasick попробуйте этот lib -> https://github.com/robert-bor/aho-corasick –

28

Я бы создать регулярное выражение из слов:

Pattern pattern = Pattern.compile("(?=.*adsf)(?=.*qwer)"); 
if (pattern.matcher(input).find()) { 
    execute(); 
} 

Для получения более подробной информации см этого ответа: https://stackoverflow.com/a/470602/660143

+0

, это только обрабатывает первое совпадение и возвращает true из того, что я могу tell, не соответствует, если ВСЕ слова находятся во входной строке. –

+1

@JimFord спасибо за указатель, ответ исправлен. –

1

Если у вас есть много подстрок смотреть вверх, то регулярное выражение вероятно, не будет большой помощью, поэтому вам лучше разместить подстроки в списке, затем повторить их и вызвать input.indexOf(substring) на каждом из них. Это возвращает индекс int, где была найдена подстрока. Если вы выкидываете каждый результат (кроме -1, что означает, что подстрока не была найдена) в TreeMap (где index - это ключ, а подстрока - это значение), вы можете получить их в порядке, вызвав keys() на карте ,

Map<Integer, String> substringIndices = new TreeMap<Integer, String>(); 
List<String> substrings = new ArrayList<String>(); 
substrings.add("asdf"); 
// etc. 

for (String substring : substrings) { 
    int index = input.indexOf(substring); 

    if (index != -1) { 
    substringIndices.put(index, substring); 
    } 
} 

for (Integer index : substringIndices.keys()) { 
    System.out.println(substringIndices.get(index)); 
} 
1

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

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

StringSearcher:

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 
import java.util.Map; 
import java.util.HashMap; 

class StringSearcher{ 
    private NeedleTree needles = new NeedleTree(-1); 
    private boolean caseSensitive; 
    private List<Integer> lengths = new ArrayList<>(); 
    private int maxLength; 

    public StringSearcher(List<String> inputs, boolean caseSensitive){ 
     this.caseSensitive = caseSensitive; 
     for(String input : inputs){ 
      if(!lengths.contains(input.length())){ 
       lengths.add(input.length()); 
      } 
      NeedleTree tree = needles; 
      for(int i = 0; i < input.length(); i++){ 
       tree = tree.child(caseSensitive ? input.codePointat(i) : Character.toLowerCase(input.codePointAt(i))); 
      } 
      tree.markSelfSet(); 
     } 
     maxLength = Collections.max(legnths); 
    } 

    public boolean matches(String haystack){ 
     if(!caseSensitive){ 
      haystack = haystack.toLowerCase(); 
     } 
     for(int i = 0; i < haystack.length(); i++){ 
      String substring = haystack.substring(i, i + maxLength); // maybe we can even skip this and use from haystack directly? 
      NeedleTree tree = needles; 
      for(int j = 0; j < substring.maxLength; j++){ 
       tree = tree.childOrNull(substring.codePointAt(j)); 
       if(tree == null){ 
        break; 
       } 
       if(tree.isSelfSet()){ 
        return true; 
       } 
      } 
     } 
     return false; 
    } 
} 

NeedleTree.java:

import java.util.HashMap; 
import java.util.Map; 

class NeedleTree{ 
    private int codePoint; 
    private boolean selfSet; 
    private Map<Integer, NeedleTree> children = new HashMap<>(); 

    public NeedleTree(int codePoint){ 
     this.codePoint = codePoint; 
    } 

    public NeedleTree childOrNull(int codePoint){ 
     return children.get(codePoint); 
    } 

    public NeedleTree child(int codePoint){ 
     NeedleTree child = children.get(codePoint); 
     if(child == null){ 
      child = children.put(codePoint, new NeedleTree(codePoint)); 
     } 
     return child; 
    } 

    public boolean isSelfSet(){ 
     return selfSet; 
    } 

    public void markSelfSet(){ 
     selfSet = true; 
    } 
} 
Смежные вопросы