1. 简介

在本篇文章中,我们将探讨如何检测一个字符串中是否包含多个关键词

2. 示例场景

假设我们有如下字符串:

String inputString = "hello there, Baeldung";

我们的目标是判断该字符串是否包含 "hello""Baeldung" 这两个关键词。

为此,我们可以将关键词放入一个数组中:

String[] words = {"hello", "Baeldung"};

⚠️注意:关键词的顺序不重要,且匹配是区分大小写的。

3. 使用 String.contains() 方法

最直观的方式是使用 String.contains() 方法。我们可以通过遍历关键词数组来逐一判断每个词是否存在于目标字符串中:

public static boolean containsWords(String inputString, String[] items) {
    boolean found = true;
    for (String item : items) {
        if (!inputString.contains(item)) {
            found = false;
            break;
        }
    }
    return found;
}

✅ 优点:逻辑清晰,适合简单场景
❌ 缺点:当关键词数量较多时,性能略差

4. 使用 String.indexOf() 方法

contains() 类似,我们也可以使用 String.indexOf() 来判断关键词是否存在。该方法返回关键词在字符串中的索引,若不存在则返回 -1

public static boolean containsWordsIndexOf(String inputString, String[] words) {
    boolean found = true;
    for (String word : words) {
        if (inputString.indexOf(word) == -1) {
            found = false;
            break;
        }
    }
    return found;
}

✅ 和 contains() 性能相近,但更灵活(可以获取位置信息)
⚠️ 不过在本例中我们并不需要索引,所以 contains() 更直观

5. 使用正则表达式

我们还可以使用 正则表达式 来实现关键词匹配。这里使用 Java 的 Pattern 类来构建匹配规则。

首先,我们为每个关键词构建一个“正向预查”(lookahead)规则:

Pattern pattern = Pattern.compile("(?=.*hello)(?=.*Baeldung)");

通用版本如下:

StringBuilder regexp = new StringBuilder();
for (String word : words) {
    regexp.append("(?=.*").append(word).append(")");
}

然后使用 matcher().find() 进行匹配:

public static boolean containsWordsPatternMatch(String inputString, String[] words) {

    StringBuilder regexp = new StringBuilder();
    for (String word : words) {
        regexp.append("(?=.*").append(word).append(")");
    }

    Pattern pattern = Pattern.compile(regexp.toString());

    return pattern.matcher(inputString).find();
}

⚠️ 正则表达式虽然强大,但性能开销较大,尤其在关键词多、文本长时表现不佳。

6. 使用 Java 8 的 Stream API 和 List

在 Java 8 中,我们可以借助 Stream API 来实现更优雅的写法。

首先,将字符串和关键词数组转换为 List

List<String> inputStringList = Arrays.asList(inputString.split(" "));
List<String> wordsList = Arrays.asList(words);

然后使用 Stream API 判断是否包含所有关键词:

public static boolean containsWordsJava8(String inputString, String[] words) {
    List<String> inputStringList = Arrays.asList(inputString.split(" "));
    List<String> wordsList = Arrays.asList(words);

    return wordsList.stream().allMatch(inputStringList::contains);
}

✅ 代码简洁,语义清晰

或者,更简单粗暴地使用 containsAll() 方法:

public static boolean containsWordsArray(String inputString, String[] words) {
    List<String> inputStringList = Arrays.asList(inputString.split(" "));
    List<String> wordsList = Arrays.asList(words);

    return inputStringList.containsAll(wordsList);
}

⚠️ 注意:这种方式只能匹配完整单词,即关键词必须由空格分隔。

7. 使用 Aho-Corasick 算法

如果关键词很多,或者性能要求高,推荐使用 Aho-Corasick 算法。它的时间复杂度为 **O(n)**,无论关键词数量多少都保持高效。

首先,添加依赖到 pom.xml

<dependency>
    <groupId>org.ahocorasick</groupId>
    <artifactId>ahocorasick</artifactId>
    <version>0.4.0</version>
</dependency>

构建关键词的 Trie 树:

Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();

解析目标字符串并获取匹配结果:

Collection<Emit> emits = trie.parseText(inputString);

打印匹配结果:

emits.forEach(System.out::println);

输出示例:

0:4=hello
13:20=Baeldung

完整实现如下:

public static boolean containsWordsAhoCorasick(String inputString, String[] words) {
    Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();

    Collection<Emit> emits = trie.parseText(inputString);
    emits.forEach(System.out::println);

    boolean found = true;
    for(String word : words) {
        boolean contains = Arrays.toString(emits.toArray()).contains(word);
        if (!contains) {
            found = false;
            break;
        }
    }

    return found;
}

📌 如果你希望匹配连续的关键词(如 "helloBaeldung"),只需移除 .onlyWholeWords() 即可。

8. 小结

本文介绍了多种在 Java 中判断字符串是否包含多个关键词的方法:

  • 使用 String.contains()indexOf():适合简单场景
  • 正则表达式:灵活但性能较差
  • Java 8 Stream API:代码优雅,但仅适用于完整单词匹配
  • Aho-Corasick 算法:高性能,适合关键词多、文本长的场景

完整代码可在 GitHub 查看。


原始标题:Check If a String Contains Multiple Keywords in Java