web-dev-qa-db-fra.com

Meilleure façon de détecter si une chaîne contient plusieurs mots

Bonjour les amis! J'essaie de créer un programme qui détecte si plusieurs mots sont dans une chaîne aussi rapidement que possible, et si c'est le cas, exécute un comportement. De préférence, je voudrais qu'il détecte également l'ordre de ces mots, mais seulement si cela peut être fait rapidement. Jusqu'à présent, voici ce que j'ai fait:

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

Comme vous pouvez le voir, le faire pour plusieurs mots deviendrait fastidieux. Est-ce le seul moyen ou existe-t-il un meilleur moyen de détecter plusieurs sous-chaînes? Et existe-t-il un moyen de détecter l'ordre?

16
Silver

Vous pouvez utiliser un tableau:

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

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

C'est aussi efficace que celui que vous avez publié mais plus facile à maintenir. La recherche d'une solution plus efficace ressemble à une micro-optimisation qui doit être ignorée jusqu'à ce qu'il soit prouvé qu'elle est effectivement un goulot d'étranglement de votre code, dans tous les cas avec un énorme jeu de chaînes, la solution pourrait être un trie.

9
Jack

Je créerais une expression régulière à partir des mots:

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

Pour plus de détails, consultez cette réponse: https://stackoverflow.com/a/470602/66014

34
Christoph Walesch

Dans Java 8 vous pourriez faire,

String[] searchFor= {"asdf", "qwer"};
String input = "asdf qwer";
public static boolean containsItemFromArray(String inputString, String[] items) {
    return Arrays.stream(input).allMatch(searchFor::contains);
}
3
Linus

Si vous avez beaucoup de sous-chaînes à rechercher, alors une expression régulière ne va probablement pas être très utile, donc vous feriez mieux de mettre les sous-chaînes dans une liste, puis de les itérer et d'appeler input.indexOf(substring) sur chacun. Cela renvoie un index int de l'endroit où la sous-chaîne a été trouvée. Si vous jetez chaque résultat (sauf -1, ce qui signifie que la sous-chaîne n'a pas été trouvée) dans un TreeMap (où index est la clé et la sous-chaîne est la valeur), alors vous pouvez récupérez-les dans l'ordre en appelant keys() sur la carte.

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
NRitH

Utilisez une structure arborescente pour contenir les sous-chaînes par point de code. Cela élimine le besoin de

Notez que cela n'est efficace que si le jeu d'aiguilles est presque constant. Cependant, il n'est pas inefficace s'il y a des ajouts ou des suppressions de sous-chaînes individuelles, mais une initialisation différente à chaque fois pour organiser un grand nombre de chaînes dans une arborescence la ralentirait certainement.

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;
    }
}
1
SOFe

Je pense qu'une meilleure approche serait quelque chose comme ça, où nous pouvons ajouter plusieurs valeurs en une seule chaîne et par index de fonction, valider index

String s = "123"; 
System.out.println(s.indexOf("1")); // 0
System.out.println(s.indexOf("2")); // 1 
System.out.println(s.indexOf("5")); // -1
0
Virendra khade

Il s'agit d'un entretien classique et d'un problème CS.

L'algorithme de Robin Karp est généralement ce dont les gens parlent en premier lors des entretiens. L'idée de base est que lorsque vous parcourez la chaîne, vous ajoutez le caractère actuel au hachage. Si le hachage correspond au hachage d'une de vos chaînes de correspondance, vous savez que vous pouvez avoir une correspondance. Cela évite d'avoir à balayer d'avant en arrière dans vos chaînes de correspondance. https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm

D'autres sujets typiques pour cette question d'entrevue sont d'envisager une structure de tri pour accélérer la recherche. Si vous avez un grand ensemble de chaînes de correspondance, vous devez toujours vérifier un grand ensemble de chaînes de correspondance. Une structure de trie est plus efficace pour effectuer cette vérification. https://en.wikipedia.org/wiki/Trie

Les algorithmes supplémentaires sont: - Aho – Corasick https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm - Commentz-Walter https: //en.wikipedia. org/wiki/Commentz-Walter_algorithm

0
Thomas Fischer