Проверьте, содержит ли строка какие-либо строки из массива


153

Как проверить строку, чтобы увидеть, содержит ли она какие-либо строки из массива?

Вместо того, чтобы использовать

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

4
Вы спрашиваете, равна ли строка какой-либо из строк в массиве или содержит какие-либо из строк в массиве?
Натикс

1
Вы хотите проверить, является ли какая-либо строка из массива подстрокой вашей входной строки? Или вы хотите проверить, равна ли ваша входная строка одной из строк в массиве? Вы можете быть более точным?
Савино Сгура

1
содержит, так что он берет строку и видит, содержит ли оно какие-либо слова из списка (хранится в виде массива строк)
arowell

Ответы:


189

РЕДАКТИРОВАТЬ: Вот обновление с использованием потокового API Java 8. Так много чище. Можно комбинировать и с регулярными выражениями.

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

Кроме того, если мы изменим тип ввода на List вместо массива, который мы можем использовать items.parallelStream().anyMatch(inputStr::contains).

Вы также можете использовать, .filter(inputStr::contains).findAny()если хотите вернуть соответствующую строку.


Оригинальный слегка датированный ответ:

Вот (ОЧЕНЬ ОСНОВНОЙ) статический метод. Обратите внимание, что в строках сравнения он чувствителен к регистру. Примитивный способ сделать это чувствительно к регистру будет звонить toLowerCase()илиtoUpperCase() на обоих входных и тестовых строк.

Если вам нужно сделать что-то более сложное, чем это, я бы порекомендовал взглянуть на классы Pattern и Matcher и научиться делать некоторые регулярные выражения. Как только вы поймете это, вы можете использовать эти классы или String.matches()вспомогательный метод.

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
Как использовать это с регулярным выражением @gnomed
Praneeth

Как мы можем сделать первую реализацию чувствительной к регистру?
thanos.a

Реализации уже чувствительны к регистру. У меня также есть инструкции о том, как сделать это без учета регистра в нижних абзацах ответа.
гномед

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

Строка Утилиты

Использование:

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

Он вернет индекс найденной строки или -1, если ничего не найдено.


7
JFI: Я надеялся, что эта реализация будет повторяться только один раз по inputString, но я посмотрел на код в StringUtils, и, к сожалению, он просто выполняет N вызовов стандартного indexOf.
alfonx

Возможно на commons3 реализация лучше!
Renanleandrof

1
Нет, все еще просто перебирает строки в org.apache.commons.lang3.StringUtils: for (int i = 0; i <searchStrs.length; i ++) {CharSequenceUtils.indexOf (str, search, 0); ....
alfonx

Это не возвращает индекс найденной строки (из массива), а только индекс позиции, в которой была найдена строка.
Плутон

33

Вы можете использовать метод String # match следующим образом:

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

16

Возможно, самым простым способом было бы преобразовать массив в java.util.ArrayList. Как только он окажется в массиве, вы можете легко использовать метод содержимого.

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

70
Это неверно OP спрашивает, stringесть ли Stringв массиве s, а не содержится ли в массиве Strings string.
Бо Грэнтэм

3
@BeauGrantham Я тоже об этом думал, но ОП использует .equals()в своем посте, что очень запутанно. Я считаю, что они должны редактировать свой вопрос
gnomed

@BeauGrantham Человек, которого я не мог поклясться, я понял проблему. Может быть, вопрос должен быть уточнен немного больше?
Рой Качух

1
Нет, этот вид обратного направления не будет работать, вы должны проверить, содержит ли строка ОДИН из указанных значений, а НЕ, если значения содержат строку.
Владимир Стажилов

2
Вопрос в обратном
Стефан ГРИЛЬОН

16

Если вы используете Java 8 или выше, вы можете положиться на Stream API, чтобы сделать такую ​​вещь:

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

Предполагая, что у вас есть большой массив Stringдля тестирования, вы также можете запустить поиск параллельно с помощью вызова parallel(), тогда код будет выглядеть так:

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

Одна странная вещь, которую я заметил, у меня есть два элемента в списке строк, я обнаружил, что, когда я использую «параллельный», он не будет возвращать правильные результаты. (даже если он содержит значение).
CharlesC

@ Чарльз. Странно, я не могу воспроизвести на моей стороне.
Николас Филотто

Я уверен, что распараллеливание потока было бы здесь неоптимальным, если бы входная строка не была длинной (~ 500 символов). Вместо этого, если бы массив был большим, было бы лучше разделить массив и запустить каждый из них параллельно.
необычайно

2

Вот одно из решений:

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

Более groovyesque подход будет использовать инъекционный в сочетании с метаклассом :

Я бы с удовольствием сказал:

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

И метод будет:

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

Если вы хотите, чтобы в любой будущей переменной String присутствовал containsAny, добавьте метод к классу вместо объекта:

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


0

И если вы ищете совпадение без учета регистра, используйте шаблон

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

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

}

0

Если вы seraching для целых слов вы можете сделать это , что работает случай без учета регистра .

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

Мы также можем сделать так:

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

Ниже должно работать для вас, предполагая, что Strings - это массив, в котором вы ищете:

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

где mykeytosearch - строка, которую вы хотите проверить на существование в массиве. mysearchComparator - это компаратор, который будет использоваться для сравнения строк.

Обратитесь к Arrays.binarySearch для получения дополнительной информации.


2
Следует отметить, что binarySearch работает только с массивом, который отсортирован либо естественным образом, либо данным компаратором (если таковой задан).
Натикс,

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.