测试一个字符串是否包含数组中的任意一个字符串

199

如何测试一个字符串是否包含数组中任何字符串?

不要使用

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

5
你是在询问一个字符串是与数组中的任何字符串相等,还是包含数组中的任何字符串? - Natix
1
你想检查数组中的任何字符串是否是输入字符串的子字符串吗?还是你想检查输入字符串是否等于数组中的某个字符串?你能更明确一些吗? - Savino Sguera
1
包含,使其获取一行并查看其中是否包含字符串数组列表中的任何单词。 - arowell
16个回答

264

编辑:这里是使用Java 8流API的更新。清爽很多。仍然可以与正则表达式结合使用。

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

另外,如果我们将输入类型更改为List而不是数组,则可以使用items.stream().anyMatch(inputStr::contains)

如果您希望返回匹配的字符串,也可以使用.filter(inputStr::contains).findAny()

重要提示:上面的代码可以使用parallelStream()实现,但大多数情况下这实际上会影响性能。有关并行流的详细信息,请参见此问题


以下是原始的答案(稍微有些过时):

下面是一个(非常基础的)静态方法。请注意,它在比较字符串时区分大小写。使其不区分大小写的一个原始方法是对输入和测试字符串都调用toLowerCase()toUpperCase()

如果您需要执行任何比这更复杂的操作,建议查看PatternMatcher类,并学习如何使用正则表达式。一旦您理解了这些内容,就可以使用这些类或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
1
parallelStream使用最小批处理大小为1024,它不会并行处理小列表。这是一个危险的操作。 - Callum Rogers
仍然更喜欢“旧”的答案,在大多数情况下更受支持且足够。 - nibbana
有没有更好的方法来检查字符?因为我必须将我的 char[] 转换为 String[],这似乎不太对。 - Brentspine
为了将其转换为所有原始字符逻辑,您可以将inputStr转换为char [],然后使用基本的“==”检查为每个字符实现“包含”作为简单的内部循环线性搜索char [] inputStr数组。如果您真的想优化性能,还可以对输入str字符进行排序和去重,并使用二进制搜索在输入char []项中搜索每个字符。 - gnomed
显示剩余3条评论

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

字符串工具类

用途:

StringUtils.indexOfAny(inputString, new String[]{item1, item2, item3})
它将返回找到的字符串的索引,如果没有找到则返回-1。

9
JFI:我希望这个实现只对inputString进行一次迭代,但是我查看了StringUtils中的代码,不幸的是它只是调用了默认的indexOf方法N次。 - alfonx
也许在commons3中实现得更好! - renanleandrof
3
不,它仍然只是在org.apache.commons.lang3.StringUtils中的字符串上进行迭代: 对于(int i = 0; i < searchStrs.length; i ++){ CharSequenceUtils.indexOf(str,search,0); .... - alfonx
这并不返回找到的字符串(从数组中)的索引,只返回找到该字符串的位置的索引。 - Pluto

35

您可以使用String#matches方法,如下所示:

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

23
如果您使用的是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); 

我注意到一件奇怪的事情,我的字符串列表中有两个项目。我发现,当我使用“parallel”时,它不会返回正确的结果(即使它包含该值)。 - CharlesC
@Charles.C 这很奇怪,我这边无法复现。 - Nicolas Filotto
我相信在这里并行化流程可能不是最优的,除非输入字符串很长(~500个字符)。相反,如果数组很大,将数组分区并并行运行每个部分可能会更好。 - lifesoordinary

13

最简单的方法可能是将该数组转换为 java.util.ArrayList。一旦它在 ArrayList 中,你就可以轻松地利用 contains 方法。

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

88
这是错误的。OP询问string中是否包含数组中的任何String,而不是数组中的任何String是否包含string - Beau Grantham
4
@BeauGrantham 我也这么想,但 OP 在他们的帖子中使用了 .equals(),这非常令人困惑。我认为他们需要编辑他们的问题。 - gnomed
@BeauGrantham 兄弟,我本来以为我理解了这个问题。也许需要更明确地阐述一下问题? - Roy Kachouh
问题很模糊,我同意。也许这确实是他们在寻找的东西。 - Beau Grantham
1
不,这种反向方法行不通,你应该检查字符串是否包含给定值中的一个,而不是检查给定值是否包含字符串。 - Vladimir Stazhilov
2
答案是相反的。 - Stéphane GRILLON

2

试试这个:

if (Arrays.stream(new String[] {item1, item2, item3}).anyMatch(inputStr::contains))

19
问题相反:目标字符串是否包含列表中的任何一个字符串。 - Basil Bourque
stream()anyMatch()需要API级别24或以上。 - Dilanka Laksiri
@DilankaLaksiri 不是很准确,这些方法自Java 8以来就已经存在了。而且最新的Java版本是16,所以你提到的“API级别24”是什么意思? - Óscar López
@ÓscarLópez 我在谈论Android API级别。 - Dilanka Laksiri
1
好的,不错。但是这个问题不是关于Android的 :) - Óscar López

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

2

自版本3.4起,Apache Common Lang 3实现了containsAny方法。


1
检查字符数组 - Saikat

1
一种更加Groovy的方法是使用injectmetaClass结合起来使用:
我想说:
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)})
}

如果您希望在将来的任何字符串变量中使用containsAny,则应将该方法添加到类而不是对象中:
String.metaClass.containsAny={notAllowedTerms->
   notAllowedTerms?.inject(false,{found,term->found || delegate.contains(term)})
}

1
我们也可以这样做:

if (string.matches("^.*?((?i)item1|item2|item3).*$"))

(?i): used for case insensitive
.*? & .*$: used for checking whether it is present anywhere in between the string.

我相信在正则表达式的两端加上 .* 就可以省略 ?$ 的使用,因为 .* 表示"零个或多个任意字符"(除了某些控制字符)。 - Max Cascone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接