Java检查字符串包含多个关键词

Java检查字符串包含多个关键词

本文介绍如何在字符串中监测多个关键词。

1. 需求说明

String inputString = "hello there, java";

我们的任务是在 inputString中查找是否有 hellojava 两个单词。把要查找的关键词放入数组中:

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

查找的顺序不重要,但应该需要大小写敏感。

2. 传统方法

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

如果包括特定关键词contains()方法返回 true。只要有一个关键词不被包括,则结束循环并返回 false。虽然这个方法需要代码较多,但它是最简单也是最快的方法。

2.2 String.indexOf()

与上面方法类似,我们可以使用 indexOf方法监测关键词的位置。实现如下:

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

如果监测到 indexOf()具体位置,否则返回 -1

2.3 使用正在表达式

下面我们使用正则表达式实现,因此需要使用 Pattern类。首先我们定义字符串表达式,因为需要匹配两个关键词,我们使用向前匹配模式:

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

通用写法:

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

然后使用 matcher()方法进行监测:

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());
    // Pattern pattern = Pattern.compile(regexp.toString(), Pattern.CASE_INSENSITIVE);
    
    return pattern.matcher(inputString).find();
}

但是正则有性能花销,如果要查找多个关键词,该方法不是最优方案。

3. Java8 和 List

我们使用Java 8 的 流 API实现,首先对前面的数据进行转换:

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

下面使用流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);
}

如果源字符串包括所有关键词,则上面管道操作返回true。部分匹配可以使用 anyMatch方法。

另外完全匹配也可以使用 Collection中的 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);
}

4. 使用AC算法(*Aho-Corasick* )

简言之,AC算法在字符串中查找多个关键词,算法复杂度为 O(n) ,与多少个关键词或长度没有关系。

增加依赖:

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

首先使用关键词数组构建Trie管道,使用 Trie数据结构:

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

然后传入 inputString参数 调用解析方法并保存结果至 emits集合中:

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

最后打印结果:

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

对应每个关键,如果查找到,则打印开始、结束位置以及关键词自身。

完整代码:

public static boolean containsWordsWithAC(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;
}

上面示例仅查找完整关键词。如果你还需要如 hellojava,那仅需要删除 onlyWholeWords方法。

5. 总结

本文介绍了多种方法实现在字符串中查找多个关键词方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值