【问题标题】:One line check if String contains bannedSubstrings一行检查String是否包含bannedSubstrings
【发布时间】:2015-05-12 09:37:25
【问题描述】:

我有一个String title 和一个List<String> bannedSubstrings。现在我想执行一行检查title 是否没有那些bannedSubstrings

我的做法:

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

不幸的是,流没有isEmpty() 方法。那么你将如何解决这个问题?有没有一条线的解决方案?

【问题讨论】:

  • @nikis:这样它会做额外的工作来找到所有在这种情况下不必要的坏词。
  • @TagirValeev 同意,​​这是我最初找到的第一个解决方案,已经发布了另一个

标签: java string lambda java-8 java-stream


【解决方案1】:

听起来你想阅读anyMatch

if (bannedSubstrings.stream().anyMatch(title::contains)) {
    // bad words!
}

反之,还有noneMatch

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

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

【讨论】:

  • 我觉得这里最好用noneMatch
  • @mkrakhin 我想这通常取决于函数的布局,但这是一个很好的建议,我会将其添加到我的答案中。
  • 当然。我刚刚提到它,因为 OP 在他的if 中检查了空虚:)
  • 另外,由于noneMatchanyMatch 不需要检查整个流,因此保持bannedSubstringstitle 中出现概率的递减顺序排序是有意义的。或者,从bannedSubstrings 长度的某个点开始,创建parallelStream 而不是stream 是有意义的。
  • @principal-ideal-domain 正则表达式方法渐近更好,因为无论您有多少禁用词,它都应该最多需要一次迭代 title,而我的建议需要一次迭代 @ 987654338@ 在最坏的情况下(即字符串正常时,因此也是正常情况!)。长话短说,我仍然认为我上面的解决方案对于任何正常用例来说都是最好的,但是如果你有大量(且固定的)禁用词和长标题,正则表达式方法很聪明并且性能相对更好。跨度>
【解决方案2】:

如果你想要一个高效的解决方案并且你有很多 bannedSubstrings,我想,将它们加入到单个正则表达式中会更快:

Pattern badWords = Pattern.compile(bannedSubstrings.stream().map(Pattern::quote)
    .collect(Collectors.joining("|")));

然后像这样使用它:

if (badWords.matcher(title).find()) {
   ...
}

这应该从您的子字符串中构建一个前缀树,因此扫描速度会大大加快。如果您不关心性能,请使用其他答案。

【讨论】:

  • 您在解决方案中假设被禁止的子字符串不包含对正则表达式具有特殊含义的字符。
  • 是的。好吧,即使不是这样,它也可以很容易地修复。已编辑。
【解决方案3】:

我想你正在寻找这样的东西:

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

}

【讨论】:

    【解决方案4】:

    您选择的答案非常好,但为了获得真正的性能,您最好将坏词列表预编译到正则表达式中。

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

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 2021-03-05
      • 2013-03-14
      • 1970-01-01
      • 2011-09-19
      • 1970-01-01
      • 2013-08-04
      相关资源
      最近更新 更多