【问题标题】:Is there a way to find the EXACT string of a word in a discord message?有没有办法在不和谐消息中找到单词的确切字符串?
【发布时间】:2020-12-18 09:29:54
【问题描述】:

目前我正在开发一个不和谐的机器人,它正在过滤消息。我的问题是在尝试过滤包含在其他单词中的单词时出现的,从而触发重复消息。

这是我的 filter.txt:

sad
sadness
sadnesses

由于“悲伤”也可以在“悲伤”中找到,所以每当写“悲伤”时,我都会误认为“悲伤”。
是否可以仅检测消息中的确切字符串?喜欢:I want to be happy, because sadness is bad → '只检测悲伤'

希望你明白我的意思。

代码:

public void onGuildMessageReceived(GuildMessageReceivedEvent e) {
    File file = new File("src/filter.txt");
    try {
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;
        while ((line = br.readLine()) != null) {
            if(!line.startsWith("#")) {
                if(e.getMessage().getContentRaw().contains(line)) {
                    User user = e.getJDA().getUserById(e.getAuthor().getIdLong());
                    e.getMessage().delete().queue();
                    user.openPrivateChannel().queue(privateChannel -> {
                        privateChannel.sendMessage("Bitte achte auf deine Sprache!").queue();
                    });
                }                   
            }
        }
    } catch (IOException e1) {}
}

【问题讨论】:

  • 请添加您的字符串匹配代码,以便我们为您提供帮助
  • 我的方法总是正则表达式。
  • 尝试查看正则表达式你会得到你想要的

标签: java discord-jda


【解决方案1】:

正如 Cardinal - Reinstate MonicaHades 已经说过的,你应该看看正则表达式。

“Regex”代表“正则表达式”,描述了字符串的搜索模式。

您可以使用正则表达式做很多事情,所以如果您想了解更多信息,请查看tutorial
(这是我在谷歌上搜索的第一个,你当然可以使用任何你喜欢的教程。)

对于您的用例,我建议如下:

首先,不要使用String.contains(),因为它只适用于字符串,不适用于正则表达式。
String.matches() 与以下正则表达式一起使用:

"(?is).*\\bSTRING\\b.*"

因为已经完成了一些转义,所以这就是没有它的正则表达式的样子:

(?is).*\bSTRING\b.*

我会解释它是如何工作的。

\b

\b 匹配单词边界。单词字符是a - zA - Z0 - 9_。这些字符的任何组合都被视为一个单词。
这样做的好处是,您可以在以下情况下匹配单词 sad

  • “我很伤心。” → 句尾的. 不影响检测。
  • “sad is my thing” → 即使是第一个单词也匹配。 (这也受到.* 的影响。)

当使用 sadness 时,它不会匹配 sad,因为单词在后面继续:

  • “我感到悲伤!” → 因为这个词没有在“sad”之后结束,所以不匹配。匹配“悲伤”会起作用。

.*

. 匹配除某些换行符以外的任何字符。 ((?s) 在这里帮助我。)
* 基本上说,它前面的部分出现零次或多次。
通过在字符串前后使用.*,正则表达式可以在字符串周围使用 any 字符或字符组合(包括无字符)。
这很重要,因为通过这种方式,单词可以放置在每个可以想象的句子中,并且无论如何都会匹配。

(?is)

?i?s 启用某些模式。
?i 使正则表达式不区分大小写。这意味着,无论是 sadnessSADNESS 还是 sAdNeSs;这三个都将匹配。
?s 启用“单行模式”,这意味着 . 也匹配所有换行符。
?i?s 可以组合为 @ 987654347@ 然后放在正则表达式前面。

您只需像这样插入您的文字,而不是 STRING

"(?is).*\\b" + line + "\\b.*"

您的代码最终将如下所示:

public void onGuildMessageReceived(GuildMessageReceivedEvent e) {
    File file = new File("src/filter.txt");
    try {
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;
        while ((line = br.readLine()) != null) {
            if(!line.startsWith("#")) {
                if(e.getMessage().getContentRaw().matches("(?is).*\\b" + line + "\\b.*")) {
                    User user = e.getJDA().getUserById(e.getAuthor().getIdLong());
                    e.getMessage().delete().queue();
                    user.openPrivateChannel().queue(privateChannel -> {
                        privateChannel.sendMessage("Bitte achte auf deine Sprache!").queue();
                    });
                }  
            }
        }
    } catch (IOException e1) {}
}

如果您希望它只为每条消息生成一条消息(因此在第一次匹配后停止),您可以在匹配一个单词并将消息发送给用户之后插入 return;

【讨论】:

  • 感谢它的工作,但如果一个句子包含多个过滤词,它会激活 3 次
  • 您能打开另一个问题或更新这个问题吗?一旦我有必要的信息,我会调查它。
  • 我修复了一些简单的问题,重新格式化并重新构建了一些部分。重写只是过程的一部分,应该让它更容易理解。我还更新了我的答案,希望对您的问题有所帮助。
【解决方案2】:

您也可以尝试使用字符串搜索算法,例如Aho-Corasick,但这需要实现正确的签名表。像这样的算法在更大的单词列表中会好很多。

请注意,此类算法很容易被规避。简单地添加空格或使用 1337 字符替换将胜过简单的单词过滤器。

【讨论】:

    猜你喜欢
    • 2021-11-04
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多