根据某些关键字过滤字符串的最快方法

时间:2019-05-22 14:20:02

标签: java regex groovy filter hashmap

我想创建一个Messenger应用程序,并且想根据某些关键字过滤传入的String。我计划使用的语言是Java,但我也可以使用Groovy。

关键字列表在文件或csv中的某个位置将是静态的。

关键字列表的大小最大为100个字(绝不会使用超过100个关键字)

传入的字符串最大为200个字节(UTF-8)

我已经看到很多帖子说使用关键字过滤字符串已经过时了。我打算做的应用程序很简单,所以我不想弄乱nlp。

关键字可以是正则表达式或普通单词。

我知道有很多方法可以做到这一点,但是我想要最快的方法。我读过一种不错的方法是使用HashMap,但我不知道如何将它与正则表达式快速组合。

例如,输入字符串可以是:

String example = "I want to gamble and drink vodka all day"

关键字列表将包含:

DRUGS
VODKA.?
GAMBLE

应过滤示例字符串,因为它包含关键字列表中的至少1个单词

编辑*

在一些回答指出使用正则表达式很慢之后,我想找到一个没有正则表达式的好的解决方案。

不使用正则表达式的一种方法是将关键字放入集合中,将传入的字符串拆分为一个数组,然后在该数组上进行迭代,并检查集合中是否包含任何数组字。

在某些情况下,这将不起作用。例如,某人可以输入“我整天喜欢赌博和喝酒”。这将不匹配。

这就是我认为正则表达式是进行单词过滤的唯一方法的原因之一...

3 个答案:

答案 0 :(得分:2)

只要您有足够的时间进行预处理,以下方法就会有效:

多字符串搜索

搜索多个字符串(针)将按字符处理输入(干草堆),并跳过将永远不会与任何指定单词匹配的部分。它不仅限于单词边界,而且经常根据干草堆的长度执行超线性运算。

最受欢迎的算法是Aho-Corasick,您可以在stringsearchalgorithms中找到一些经过良好测试的算法

DFA-Regular-Expression-Search

使用正则表达式进行搜索的DFA(确定性有限自动机)引擎逐个字符地处理输入(干草堆)并更新引擎自动机,它从不跳过任何部分,因此永远不会在线性运行时间短的情况下执行。 / p>

正则表达式搜索的主要优点是您可以轻松指定模式而不是单词。主要缺点是预处理时间(最坏情况是图案长度的指数)。前一段时间,我花了几分钟甚至几个小时来等待复杂的正则表达式编译。

您可以在patternsearchalgorithmsbrics上找到正则表达式搜索

答案 1 :(得分:1)

一种解决方案(肯定不是最快,但也许足够好)是将列表中的每个条目都视为正则表达式,并将所有正则表达式与|一起加入以仅对单个正则表达式find()执行matcher

Pattern pattern = Pattern.compile("DRUGS|VODKA.?|GAMBLE");
Matcher matcher = pattern.matcher(input);
boolean result = matcher.find();

答案 2 :(得分:0)

尝试使用正则表达式查找完全匹配的单词:

import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SoRegex {
    // The static set of keywords.
    static final Set<String> keywords = Set.of("DRUGS", "VODKA", "GABMBLE");

    public static void main(String[] args) {
        // Construct a regular expression that matches any of the keywords anywhere. Use
        // word boundaries '\b'.
        StringBuilder sb = new StringBuilder("^.*(\\b").append(String.join("\\b|\\b", keywords)).append("\\b).*$");
        Pattern p = Pattern.compile(sb.toString());

        String input = "I want to gamble and drink vodka all day";

        // Convert the input to uppercase since the keywords are uppercase.
        Matcher matcher = p.matcher(input.toUpperCase());
        System.out
                .println(String.format("input '%s' matches pattern '%s': %b", input, p.toString(), matcher.matches()));
    }

}

输出:

input 'I want to gamble and drink vodka all day' matches pattern '^.*(\bGABMBLE\b|\bDRUGS\b|\bVODKA\b).*$': true

其他类型的关键字留给读者练习。