Teste si une chaîne contient l'une des chaînes d'un tableau


153

Comment tester une chaîne pour voir si elle contient l'une des chaînes d'un tableau?

À la place d'utiliser

if (string.contains(item1) || string.contains(item2) || string.contains(item3))

4
Demandez-vous si une chaîne est égale à l'une des chaînes du tableau ou contient l' une des chaînes du tableau?
Natix

1
Vous voulez vérifier si une chaîne du tableau est une sous-chaîne de votre chaîne d'entrée? Ou vous voulez vérifier si votre chaîne d'entrée est égale à l' une des chaînes du tableau? Pouvez-vous être plus précis?
Savino Sguera

1
contient, de sorte qu'il prenne une ligne et voit s'il contient l'un des mots d'une liste (stocké sous forme de tableau de chaînes)
arowell

Réponses:


189

EDIT: Voici une mise à jour utilisant l'API Java 8 Streaming. Tellement plus propre. Peut également être combiné avec des expressions régulières.

public static boolean stringContainsItemFromList(String inputStr, String[] items) {
    return Arrays.stream(items).parallel().anyMatch(inputStr::contains);
}

De plus, si nous changeons le type d'entrée en List au lieu d'un tableau, nous pouvons utiliser items.parallelStream().anyMatch(inputStr::contains).

Vous pouvez également utiliser .filter(inputStr::contains).findAny()si vous souhaitez renvoyer la chaîne correspondante.


Réponse originale légèrement datée:

Voici une méthode statique (TRÈS BASIQUE). Notez qu'il est sensible à la casse sur les chaînes de comparaison. Une façon primitive de le rendre insensible à la casse serait d'appeler toLowerCase()ou toUpperCase()à la fois sur les chaînes d'entrée et de test.

Si vous avez besoin de faire quelque chose de plus compliqué que cela, je vous recommande de regarder les classes Pattern et Matcher et d'apprendre à faire des expressions régulières. Une fois que vous les avez compris, vous pouvez utiliser ces classes ou la String.matches()méthode d'assistance.

public static boolean stringContainsItemFromList(String inputStr, String[] items)
{
    for(int i =0; i < items.length; i++)
    {
        if(inputStr.contains(items[i]))
        {
            return true;
        }
    }
    return false;
}

1
Comment l'utiliser avec une expression régulière @gnomed
Praneeth

Comment rendre la première implémentation sensible à la casse?
thanos.a

Les implémentations sont déjà sensibles à la casse. J'ai également des instructions sur la façon de le rendre insensible à la casse dans les paragraphes inférieurs de la réponse.
gnomed

52
import org.apache.commons.lang.StringUtils;

Utils de chaîne

Utilisation:

StringUtils.indexOfAny(inputString, new String[]{item1, item2, item3})

Il renverra l'index de la chaîne trouvée ou -1 si aucun n'est trouvé.


7
JFI: J'espérais que cette implémentation n'itérerait qu'une seule fois sur inputString, mais j'ai regardé le code dans StringUtils, et malheureusement, il ne fait que N appels de l'indexOf par défaut.
alfonx

Peut-être que sur commons3, la mise en œuvre est meilleure!
renanleandrof

1
Non, répète simplement les chaînes dans org.apache.commons.lang3.StringUtils: for (int i = 0; i <searchStrs.length; i ++) {CharSequenceUtils.indexOf (str, search, 0); ....
alfonx

Cela ne renvoie pas l'index de la chaîne trouvée (à partir du tableau), seul l'index de la position à laquelle la chaîne a été trouvée.
Pluton le

33

Vous pouvez utiliser la méthode String # matches comme ceci:

System.out.printf("Matches - [%s]%n", string.matches("^.*?(item1|item2|item3).*$"));

16

Le moyen le plus simple serait probablement de convertir le tableau en java.util.ArrayList. Une fois qu'il est dans une arraylist, vous pouvez facilement utiliser la méthode contains.

public static boolean bagOfWords(String str)
{
    String[] words = {"word1", "word2", "word3", "word4", "word5"};  
    return (Arrays.asList(words).contains(str));
}

70
Ceci est une erreur. OP demande si stringcontient des Strings dans le tableau, pas si des Strings dans le tableau contiennent string.
Beau Grantham

3
@BeauGrantham Je pensais cela aussi, mais l'OP utilise .equals()dans leur message, ce qui est très déroutant. Je pense qu'ils doivent modifier leur question
gnomed

@BeauGrantham Man Je n'ai pas pu jurer que j'avais compris le problème. Peut-être que la question doit être clarifiée un peu plus?
Roy Kachouh

1
Non, ce type de direction inverse ne fonctionnera pas, vous devriez vérifier si String contient UNE des valeurs données et NON si les valeurs données contiennent la chaîne.
Vladimir Stazhilov

2
La question est le contraire
Stéphane GRILLON

16

Si vous utilisez Java 8 ou supérieur, vous pouvez compter sur l' API Stream pour faire une telle chose:

public static boolean containsItemFromArray(String inputString, String[] items) {
    // Convert the array of String items as a Stream
    // For each element of the Stream call inputString.contains(element)
    // If you have any match returns true, false otherwise
    return Arrays.stream(items).anyMatch(inputString::contains);
}

En supposant que vous ayez un grand tableau de big Stringà tester, vous pouvez également lancer la recherche en parallèle en appelant parallel(), le code serait alors:

return Arrays.stream(items).parallel().anyMatch(inputString::contains); 

Une chose étrange que j'ai remarquée, j'ai deux éléments dans la liste des chaînes, j'ai découvert que lorsque j'utilise `` parallèle '', cela ne renvoie pas les bons résultats. (même s'il contient la valeur).
CharlesC

@ Charles.C c'est bizarre que je ne peux pas reproduire de mon côté.
Nicolas Filotto

Je suis à peu près sûr que la parallélisation du flux serait sous-optimale ici à moins que la chaîne d'entrée ne soit longue (~ 500 caractères). Au lieu de cela, si le tableau était grand, il serait probablement préférable de partitionner le tableau et d'exécuter chacun d'eux en parallèle.
lifesoordinary

2

Voici une solution:

public static boolean containsAny(String str, String[] words)
{
   boolean bResult=false; // will be set, if any of the words are found
   //String[] words = {"word1", "word2", "word3", "word4", "word5"};

   List<String> list = Arrays.asList(words);
   for (String word: list ) {
       boolean bFound = str.contains(word);
       if (bFound) {bResult=bFound; break;}
   }
   return bResult;
}


1

Une approche plus groovyesque serait d'utiliser inject en combinaison avec métaclasse :

J'adorerais dire:

String myInput="This string is FORBIDDEN"
myInput.containsAny(["FORBIDDEN","NOT_ALLOWED"]) //=>true

Et la méthode serait:

myInput.metaClass.containsAny={List<String> notAllowedTerms->
   notAllowedTerms?.inject(false,{found,term->found || delegate.contains(term)})
}

Si vous avez besoin que containsAny soit présent pour toute future variable String, ajoutez la méthode à la classe au lieu de l'objet:

String.metaClass.containsAny={notAllowedTerms->
   notAllowedTerms?.inject(false,{found,term->found || delegate.contains(term)})
}

1

Essaye ça:

if (Arrays.asList(item1, item2, item3).stream().anyMatch(string::contains))

15
La question est le contraire: la chaîne cible contient-elle l'une des chaînes de la liste.
Basil Bourque

1
La question est le contraire
Stéphane GRILLON

0

Et si vous recherchez une correspondance insensible à la casse, utilisez le modèle

Pattern pattern = Pattern.compile("\\bitem1 |item2\\b",java.util.regex.Pattern.CASE_INSENSITIVE);

    Matcher matcher = pattern.matcher(input);
    if(matcher.find() ){ 

}

0

Si vous seraching pour entiers mots que vous pouvez faire ce qui fonctionne le cas insensible .

private boolean containsKeyword(String line, String[] keywords)
{
    String[] inputWords = line.split(" ");

    for (String inputWord : inputWords)
    {
        for (String keyword : keywords)
        {
            if (inputWord.equalsIgnoreCase(keyword))
            {
                return true;
            }
        }
    }

    return false;
}

0

On peut aussi faire comme ça:

if (string.matches("^.*?((?i)item1|item2|item3).*$"))
(?i): used for case insensitive
.*? & .*$: used for checking whether it is present anywhere in between the string.

-3

Ce qui suit devrait fonctionner pour vous en supposant que Strings est le tableau dans lequel vous recherchez:

Arrays.binarySearch(Strings,"mykeytosearch",mysearchComparator);

où mykeytosearch est la chaîne dont vous souhaitez tester l'existence dans le tableau. mysearchComparator - est un comparateur qui serait utilisé pour comparer des chaînes.

Reportez-vous à Arrays.binarySearch pour plus d'informations.


2
Il convient de noter que binarySearch ne fonctionne que sur des tableaux triés, soit naturellement, soit par le comparateur donné (si tel est le cas).
Natix

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.