一行代码检查字符串是否包含禁用的子字符串

3

我有一个String title和一个List<String> bannedSubstrings。现在我想要一行代码检查title是否不包含这些bannedSubstrings

我的方法:

if(bannedSubstrings.stream().filter(bannedSubstring -> title.contains(bannedSubstring)).isEmpty()){
    ...
}

很不幸,流没有isEmpty()方法。那么你该如何解决这个问题呢?有没有一行代码的解决方案呢?


@nikis:这样做会多做一些工作,找到所有不良词汇,但在这种情况下是不必要的。 - Tagir Valeev
@TagirValeev同意,这是我首先想到的解决方案,已经发布了另一个。 - nikis
4个回答

8
听起来你想了解关于 anyMatch 的内容:
if (bannedSubstrings.stream().anyMatch(title::contains)) {
    // bad words!
}

相反地,这里也有一个noneMatch

if (bannedSubstrings.stream().noneMatch(title::contains)) {
    // no bad words :D
}

如果title是一个很长的字符串,这并不是非常高效的(但我想标题通常不应该太长)。


1
我认为在这里使用 noneMatch 更好。 - mkrakhin
1
@mkrakhin 我想这取决于函数的布局,但这是一个好建议,我会把它加入到我的答案中。 - gustafc
1
当然。我只是提到了它,因为 OP 在他的 if 中检查了空值 :) - mkrakhin
在我的情况下,title很短,检查不会花费太多时间。但是,为了扩大我对高效算法的一般知识,我对更高效的解决方案感兴趣。您认为Tagir Valeev的正则表达式方法怎么样? - principal-ideal-domain
1
另外,由于noneMatchanyMatch不需要检查整个流,因此将bannedSubstrings按照出现概率递减的顺序排序是有意义的。或者,从某个bannedSubstrings长度开始,创建parallelStream而不是stream也是有意义的。 - mkrakhin
1
@principal-ideal-domain 正则表达式方法在渐进意义下更好,因为它最多只需要一次迭代通过“title”,无论你有多少禁用词,而我的建议在最坏情况下(字符串是OK时,也是正常情况)需要每个禁用词一次迭代通过“title”。长话短说,我仍然认为我的解决方案对于任何正常使用情况都是最好的,但是如果您有一个大型(且固定)的禁用词集和一个长标题,则正则表达式方法聪明且相对更好。 - gustafc

4
如果您想要一个高效的解决方案,并且有很多bannedSubstrings,我想,将它们合并成单个正则表达式会更快,就像这样:
Pattern badWords = Pattern.compile(bannedSubstrings.stream().map(Pattern::quote)
    .collect(Collectors.joining("|")));

然后像这样使用它:
if (badWords.matcher(title).find()) {
   ...
}

这将从您的子字符串构建前缀树,因此扫描速度将显着提高。如果性能在您的情况下不是问题,请使用其他答案。

你在解决方案中假设被禁用的子字符串不包含与正则表达式相关的具有特殊意义的字符。 - principal-ideal-domain
1
是的。即使不是这种情况,也可以轻松解决。已编辑。 - Tagir Valeev

3
我想您可能正在寻找类似以下内容的东西:

我猜您是在寻找与此类似的东西:

if(bannedSubstrings.stream().anyMatch(title::contains)){

}

0
你选择的答案很不错,但为了实现真正的性能,最好将坏单词列表预编译成正则表达式。
public class BannedWordChecker {
    public final Pattern bannedWords;

    public BannedWordChecker(Collection<String> bannedWords) {
        this.bannedWords =
            Pattern.compile(
                bannedWords.stream()
                    .map(Pattern::quote)
                    .collect(Collectors.joining("|")));
    }

    public boolean containsBannedWords(String string) {
        return bannedWords.matcher(string).find();
    }
}

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