Sprawdź, czy ciąg zawiera którykolwiek z ciągów z tablicy


153

Jak przetestować ciąg, aby sprawdzić, czy zawiera którykolwiek z ciągów z tablicy?

Zamiast używać

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

4
Czy pytasz, czy ciąg jest równy dowolnemu ciągowi w tablicy lub zawiera którykolwiek z ciągów z tablicy?
Natix

1
Chcesz sprawdzić, czy dowolny ciąg z tablicy jest podłańcuchem Twojego ciągu wejściowego? A może chcesz sprawdzić, czy ciąg wejściowy jest równy jednemu z ciągów w tablicy? Czy możesz być bardziej precyzyjny?
Savino Sguera

1
zawiera, więc przyjmuje linię i sprawdza, czy zawiera którekolwiek ze słów z listy (przechowywane jako tablica ciągów)
arowell

Odpowiedzi:


188

EDYCJA: Oto aktualizacja wykorzystująca API strumieniowania Java 8. O wiele czystsze. Nadal można go również łączyć z wyrażeniami regularnymi.

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

Ponadto, jeśli zmienimy typ danych wejściowych na List zamiast tablicy, której możemy użyć items.parallelStream().anyMatch(inputStr::contains) .

Możesz również użyć, .filter(inputStr::contains).findAny()jeśli chcesz zwrócić pasujący ciąg.


Oryginalna nieco przestarzała odpowiedź:

Oto (BARDZO PODSTAWOWA) metoda statyczna. Zauważ, że w łańcuchach porównania rozróżniana jest wielkość liter. Prymitywny sposób, aby to wielkość liter ma znaczenie byłoby zadzwonić toLowerCase()lubtoUpperCase() na obu ciągów wejściowych i testowych.

Jeśli potrzebujesz zrobić coś bardziej skomplikowanego niż to, polecam przyjrzenie się klasom Pattern i Matcher i nauczenie się wykonywania wyrażeń regularnych. Gdy je zrozumiesz, możesz użyć tych klas lub String.matches()metody pomocniczej.

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
Jak używać tego z wyrażeniem regularnym @gnomed
Praneeth

Jak w pierwszej implementacji uwzględnić wielkość liter?
thanos.

W implementacjach jest już rozróżniana wielkość liter. Mam również instrukcje, jak sprawić, by wielkość liter nie była rozróżniana w dolnych akapitach odpowiedzi.
gnomed

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

Narzędzia sznurkowe

Posługiwać się:

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

Zwróci indeks znalezionego ciągu lub -1, jeśli żaden nie zostanie znaleziony.


7
JFI: Miałem nadzieję, że ta implementacja dokona iteracji tylko raz po łańcuchu inputString, ale przyjrzałem się kodowi w StringUtils i niestety wykonuje on tylko wywołania N domyślnego indexOf.
alfonx

Może na commons3 implementacja jest lepsza!
renanleandrof

1
Nie, nadal wykonuje iterację po łańcuchach w org.apache.commons.lang3.StringUtils: for (int i = 0; i <searchStrs.length; i ++) {CharSequenceUtils.indexOf (str, search, 0); ....
alfonx

To nie zwraca indeksu znalezionego ciągu (z tablicy), tylko indeks pozycji, w której znaleziono ciąg.
Pluto


16

Najłatwiejszym sposobem byłoby prawdopodobnie przekonwertowanie tablicy na java.util.ArrayList. Gdy znajdzie się na liście arraylistów, możesz łatwo wykorzystać metodę zawierającą.

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

70
To jest niepoprawne. OP pyta, czy stringzawiera jakieś Strings w tablicy, a nie czy zawiera jakieś Strings w tablicy string.
Beau Grantham

3
@BeauGrantham Też o tym myślałem, ale OP używa .equals()w swoim poście, co jest bardzo mylące. Myślę, że muszą zmienić swoje pytanie
gnomed

@BeauGrantham Man Nie mogę przysiąc, że zrozumiałem problem. Może pytanie wymaga nieco dokładniejszego wyjaśnienia?
Roy Kachouh

1
Nie, ten rodzaj odwrotnego kierunku nie zadziała, powinieneś sprawdzić, czy String zawiera JEDNĄ z podanych wartości i NIE, jeśli podane wartości zawierają łańcuch.
Vladimir Stazhilov

2
Pytanie jest odwrotne
Stéphane GRILLON

16

Jeśli używasz Java 8 lub nowszej, możesz polegać na Stream API, aby zrobić coś takiego:

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

Zakładając, że masz dużą tablicę dużych Stringdo przetestowania, możesz również uruchomić wyszukiwanie równolegle, wywołując parallel(), kod wyglądałby wtedy:

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

Jedna dziwna rzecz, którą zauważyłem, mam dwie pozycje na liście ciągów, dowiedziałem się, że kiedy używam 'parallel', nie zwróci to poprawnych wyników. (nawet jeśli zawiera wartość).
CharlesC

@ Charles.C to dziwne, którego nie mogę odtworzyć po swojej stronie.
Nicolas Filotto

Jestem prawie pewien, że zrównoleglenie strumienia byłoby tutaj nieoptymalne, chyba że ciąg wejściowy byłby długi (~ 500 znaków). Zamiast tego, gdyby tablica była duża, prawdopodobnie lepiej byłoby podzielić tablicę na partycje i uruchomić każdą z nich równolegle.
lifesostanding

2

Oto jedno rozwiązanie:

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

Bardziej groovyesque byłoby użycie wstrzyknięcia w połączeniu z metaClass :

Bardzo chciałbym powiedzieć:

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

A metoda byłaby taka:

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

Jeśli chcesz, aby zawierała ona wszystkie przyszłe zmienne typu String, dodaj metodę do klasy zamiast do obiektu:

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


0

A jeśli szukasz dopasowania bez rozróżniania wielkości liter, użyj wzorca

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

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

}

0

Jeśli szukasz całych słów, możesz to zrobić bez rozróżniania wielkości liter .

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

Możemy też zrobić tak:

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

Poniższe powinno zadziałać, zakładając, że ciągi znaków to tablica, w której szukasz:

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

gdzie mykeytosearch to ciąg, który chcesz sprawdzić pod kątem istnienia w tablicy. mysearchComparator - to komparator, który byłby używany do porównywania ciągów.

Więcej informacji zawiera Arrays.binarySearch .


2
Należy zauważyć, że binarySearch działa tylko na tablicach posortowanych naturalnie lub przez dany komparator (jeśli taki jest podany).
Natix

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.