Test if a string contains any of the strings from an array
Asked Answered
B

16

202

How do I test a string to see if it contains any of the strings from an array?

Instead of using

if (string.contains(item1) || string.contains(item2) || string.contains(item3))
Behn answered 24/1, 2012 at 18:32 Comment(3)
Are you asking if a string is equal to any of the strings in the array, or contains any of the strings from in the array?Bonn
You want to check if any string from the array is a substring of your input string? Or you want to check if your input string equals one of the string in the array? Can you be more precise?Dudek
contains, so that it takes a line and sees if it contains any of the words from a list (stored as an array of strings)Behn
T
266

EDIT: Here is an update using the Java 8 Streaming API. So much cleaner. Can still be combined with regular expressions too.

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

Also, if we change the input type to a List instead of an array we can use items.stream().anyMatch(inputStr::contains).

You can also use .filter(inputStr::contains).findAny() if you wish to return the matching string.

Important: the above code can be done using parallelStream() but most of the time this will actually hinder performance. See this question for more details on parallel streaming.


Original slightly dated answer:

Here is a (VERY BASIC) static method. Note that it is case sensitive on the comparison strings. A primitive way to make it case insensitive would be to call toLowerCase() or toUpperCase() on both the input and test strings.

If you need to do anything more complicated than this, I would recommend looking at the Pattern and Matcher classes and learning how to do some regular expressions. Once you understand those, you can use those classes or the String.matches() helper method.

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;
}
Threequarter answered 24/1, 2012 at 23:44 Comment(8)
How to use it with regular expression @ThreequarterMilldam
How can we make the first implementation case sensitive ?Copyholder
The implementations are case sensitive already. I also have instructions for how to make it case insensitive in the bottom paragraphs of the answer.Threequarter
parallelStream uses a minimum batch size of 1024, it won't actually parallelise small lists. It's a footgun.Ganof
@CallumRogers true, I kind of left it in just so people think about it, but agree the vast majority of the time it will not make much difference (or actually be a detriment) compared to a non-parallel stream. Will try to call that out more in the answer.Threequarter
Still prefer the "old" answer, more supported and sufficient in most cases.Gluten
Is there a better way if you want to check it for characters? Because I would have to convert my char[] to String[] which doesn't seem right.Shufu
To make it all primitve char logic you could convert the inputStr to a char[] and then implement the "contains" as a simple inner loop linear search of the char[] inputStr array with a primitive == check for each character. If you really wanted to optimize performance you could also sort and deduplicate the input str characters and search it using binary search for each character in your input char[] items.Threequarter
P
60
import org.apache.commons.lang.StringUtils;

String Utils

Use:

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

It will return the index of the string found or -1 if none is found.

Promotive answered 28/5, 2015 at 13:17 Comment(4)
JFI: I hoped this implementation to iterate only once over the inputString, but I looked at the code in StringUtils, and sadly it's just doing N calls of the default indexOf.Yeseniayeshiva
Maybe on commons3 the implementation is better!Promotive
Nope, still just iterates over the Strings in org.apache.commons.lang3.StringUtils: for (int i = 0; i < searchStrs.length; i++) { CharSequenceUtils.indexOf(str, search, 0); ....Yeseniayeshiva
This does not return the index of the string found (from the array), only the index of the position the string was found at.Crepitate
P
36

You can use String#matches method like this:

System.out.printf("Matches - [%s]%n", string.matches("^.*?(item1|item2|item3).*$"));
Premarital answered 24/1, 2012 at 18:38 Comment(0)
B
23

If you use Java 8 or above, you can rely on the Stream API to do such thing:

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);
}

Assuming that you have a big array of big String to test you could also launch the search in parallel by calling parallel(), the code would then be:

return Arrays.stream(items).parallel().anyMatch(inputString::contains); 
Barrie answered 31/8, 2016 at 7:42 Comment(3)
One strange thing I noticed, I have two item in the String list, I found out, when i use 'parallel' it will not return the correct results. (even if it contains the value).Pectin
@Charles.C that's weird I can't reproduce on my side.Barrie
I am pretty sure parallelizing the stream would be suboptimal here unless input string was long (~ 500 chars). Instead if the array was large, It would probably be better to partitition the array and run each of those in parallel.Salazar
Y
13

The easiest way would probably be to convert the array into a java.util.ArrayList. Once it is in an arraylist, you can easily leverage the contains method.

public static boolean bagOfWords(String str)
{
    String[] words = {"word1", "word2", "word3", "word4", "word5"};  
    return (Arrays.asList(words).contains(str));
}
Yea answered 24/1, 2012 at 18:36 Comment(6)
This is incorrect. OP is asking if string contains any Strings in the array, not if any Strings in the array contain string.Zoroaster
@BeauGrantham I was thinking this too, but the OP is using .equals() in their post, which is very confusing. I reckon they need to edit their questionThreequarter
@BeauGrantham Man I couldn't sworn I understood the problem. Maybe the question needs to be clarified a bit more?Yea
The question is vague, I agree. Maybe this is indeed what they are looking for.Zoroaster
No, this kind of inverse direction won't work, you should check if String contains ONE of the values given and NOT if the values gives contain the string.Pasargadae
Question is the oppositeScrophulariaceous
F
2

Try this:

if (Arrays.stream(new String[] {item1, item2, item3}).anyMatch(inputStr::contains))
Feola answered 24/1, 2012 at 18:37 Comment(5)
Question is the opposite: Does the target string contain any of the list’s strings.Besmear
stream() and anyMatch() requires API level 24 or aboveEliathas
@DilankaLaksiri not really, those methods have been available since Java 8. And the latest version of Java is 16, so what "API level 24" are you referring to?Bloomery
@ÓscarLópez I'm talking about the Android API level.Eliathas
Ok, good. But this question was not about Android :)Bloomery
E
2

Here is one 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;
}
Erund answered 6/1, 2016 at 11:10 Comment(0)
K
2

Since version 3.4 Apache Common Lang 3 implement the containsAny method.

Koppel answered 23/5, 2018 at 11:52 Comment(1)
That checks for Char arrayHesitancy
M
1

A more groovyesque approach would be to use inject in combination with metaClass:

I would to love to say:

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

And the method would be:

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

If you need containsAny to be present for any future String variable then add the method to the class instead of the object:

String.metaClass.containsAny={notAllowedTerms->
   notAllowedTerms?.inject(false,{found,term->found || delegate.contains(term)})
}
Mirilla answered 18/11, 2013 at 10:44 Comment(0)
H
1

We can also do like this:

if (string.matches("^.*?((?i)item1|item2|item3).*$"))
(?i): used for case insensitive
.*? & .*$: used for checking whether it is present anywhere in between the string.
Heterosexual answered 14/7, 2020 at 12:9 Comment(1)
I believe wrapping the ends with .* makes the ? and $ redundant, as .* means "zero or more of any characters" (with some control char caveats)Latterly
V
0

And if you are looking for case insensitive match, use pattern

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

Matcher matcher = pattern.matcher(input);
if (matcher.find()) { 
    ...
}
Vanhorn answered 3/2, 2017 at 14:17 Comment(0)
C
0

If you are seraching for whole words you can do this that works case insensitive.

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;
}
Copyholder answered 20/11, 2019 at 20:24 Comment(0)
E
0

in Kotlin

if ( arrayOf("one", "two", "three").find{ "onetw".contains(it) } != null ) {
    doStuff()
}
Elocution answered 22/9, 2021 at 14:26 Comment(2)
Not sure if adding a badly formatted answer in a different language than what had been asked for 9 years ago is appropriate.Kratzer
@ThomasHirsch Why wouldn't it be? It's straightforward and definitely more useful todayAstigmia
R
0

In Apache common lang 3 support check contains any Strings. Try it:

import org.apache.commons.lang3.StringUtils;

...

if(StringUtils.containsAny(string, item1, item2, item3)){
   // your code
}
Recessional answered 3/8, 2023 at 6:58 Comment(0)
M
-3

The below should work for you assuming Strings is the array that you are searching within:

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

where mykeytosearch is the string that you want to test for existence within the array. mysearchComparator - is a comparator that would be used to compare strings.

Refer to Arrays.binarySearch for more information.

Maculate answered 24/1, 2012 at 18:43 Comment(1)
It should be noted that binarySearch works only on array that are sorted, either naturally or by the given comparator (if such is given).Bonn
B
-6
if (Arrays.asList(array).contains(string))
Ballman answered 24/1, 2012 at 18:37 Comment(1)
Question is the opposite: Does the target string contain any of the list’s strings.Besmear

© 2022 - 2024 — McMap. All rights reserved.