Перевірте, чи містить рядок якийсь із рядків із масиву


153

Як перевірити рядок, щоб побачити, чи містить він будь-який рядок із масиву?

Замість використання

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

4
Ви запитуєте, чи рядок дорівнює будь-якому з рядків у масиві чи містить будь-який з рядків у масиві?
Натікс

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

1
містить, так що він займає рядок і бачить, чи містить він якесь слово зі списку (зберігається як масив рядків)
arowell

Відповіді:


188

EDIT: Ось оновлення за допомогою потокового API Java 8. Настільки чистіше. Ще можна поєднувати і з регулярними виразами.

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

Крім того, якщо ми змінимо тип введення на Список замість масиву, який ми можемо використовувати items.parallelStream().anyMatch(inputStr::contains).

Ви також можете використовувати, .filter(inputStr::contains).findAny()якщо ви хочете повернути відповідний рядок.


Оригінальна трохи датована відповідь:

Ось (ДУЖЕ ОСНОВНИЙ) статичний метод. Зауважте, що він відрізняється великими літерами до рядків порівняння. Примітивний спосіб зробити це відчутно до регістру буде дзвонити toLowerCase()або toUpperCase()на обох вхідних і тестових рядків.

Якщо вам потрібно зробити щось складніше, ніж це, я б рекомендував переглянути класи Шаблон і Матч та навчитися робити деякі регулярні вирази. Після того, як ви зрозумієте це, ви можете скористатись цими класами або 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

Реалізації вже залежать від регістру. У нижчих абзацах відповіді я також маю інструкції, як зробити це нечутливим.
gnomed

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

String Utils

Використання:

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, пошук, 0); ....
alfonx

Це не повертає індекс рядка, знайденого (з масиву), лише індекс позиції, в якій знайдено рядок.
Плутон


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в масиві який-небудь Strings , а не, якщо який-небудь s в масиві string.
Beau Grantham

3
@BeauGrantham Я теж думав про це, але ОП використовує .equals()свою посаду, що дуже заплутано. Я вважаю, що їм потрібно відредагувати своє запитання
gnomed

@BeauGrantham Man Я не міг скласти присягу, я зрозумів проблему. Можливо, питання потрібно уточнити ще трохи?
Рой Качух

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

Одне дивне, що я помітив, у мене в списку String є два пункти, я виявив, що коли я використовую "паралельно", це не призведе до правильних результатів. (навіть якщо воно містить значення).
CharlesC

@ Charles.C це дивно, що я не можу відтворити свою сторону.
Ніколя Філотто

Я впевнений, що паралелізація потоку була б тут неоптимальною, якщо тільки вхідний рядок не був довгим (~ 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

Більш бурхливим підходом було б використання ін'єкцій у поєднанні з metaClass :

Я хотів би сказати:

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

Якщо вам потрібно, щоб присутній містить ContentAny для будь-якої майбутньої змінної String, тоді додайте метод до класу замість об'єкта:

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.