【问题标题】:Removing strings from another string in java从java中的另一个字符串中删除字符串
【发布时间】:2014-06-15 12:25:47
【问题描述】:

假设我有这个单词列表:

 String[] stopWords = new String[]{"i","a","and","about","an","are","as","at","be","by","com","for","from","how","in","is","it","not","of","on","or","that","the","this","to","was","what","when","where","who","will","with","the","www"};

比我有文字

 String text = "I would like to do a nice novel about nature AND people"

是否有方法可以匹配 stopWords 并在忽略大小写的情况下删除它们;像这样的地方吗?:

 String noStopWordsText = remove(text, stopWords);

结果:

 " would like do nice novel nature people"

如果您知道 regex 会很好用,但我真的更喜欢像 commons 解决方案这样更注重性能的解决方案。

顺便说一句,我现在正在使用这种缺乏适当的不敏感大小写处理的公共方法:

 private static final String[] stopWords = new String[]{"i", "a", "and", "about", "an", "are", "as", "at", "be", "by", "com", "for", "from", "how", "in", "is", "it", "not", "of", "on", "or", "that", "the", "this", "to", "was", "what", "when", "where", "who", "will", "with", "the", "www", "I", "A", "AND", "ABOUT", "AN", "ARE", "AS", "AT", "BE", "BY", "COM", "FOR", "FROM", "HOW", "IN", "IS", "IT", "NOT", "OF", "ON", "OR", "THAT", "THE", "THIS", "TO", "WAS", "WHAT", "WHEN", "WHERE", "WHO", "WILL", "WITH", "THE", "WWW"};
 private static final String[] blanksForStopWords = new String[]{"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};

 noStopWordsText = StringUtils.replaceEach(text, stopWords, blanksForStopWords);     

【问题讨论】:

  • 你的字符串中有标点符号吗?
  • 您是否有一些硬数字表明正则表达式解决方案性能不足,或者这只是过早的优化?我的意思是,这绝对不是 性能最高的解决方案,但除非这就是你所做的一切并且你需要每秒执行 10K 次,否则我敢打赌这不是问题。

标签: java string


【解决方案1】:

使用停用词创建正则表达式,使其不区分大小写,然后使用匹配器的replaceAll 方法将所有匹配项替换为空字符串

import java.util.regex.*;

Pattern stopWords = Pattern.compile("\\b(?:i|a|and|about|an|are|...)\\b\\s*", Pattern.CASE_INSENSITIVE);
Matcher matcher = stopWords.matcher("I would like to do a nice novel about nature AND people");
String clean = matcher.replaceAll("");

模式中的...只是我偷懒,继续停用词列表。

另一种方法是遍历所有停用词并使用StringreplaceAll 方法。这种方法的问题是replaceAll 将为每次调用编译一个新的正则表达式,因此在循环中使用效率不是很高。此外,当您使用StringreplaceAll 时,您不能传递使正则表达式不区分大小写的标志。

编辑:我在模式周围添加了\b 以使其仅匹配整个单词。我还添加了\s* 以使其之后的任何空格都被覆盖,这可能不是必需的。

【讨论】:

  • 是的,应该。我在正则表达式中有一个错误,在 Java 中 \b 需要是 \\b,我忘记了。但现在应该可以了。
【解决方案2】:

您可以制作一个 reg 表达式来匹配所有停止 单词 [例如 a ,注意这里的空格]并以

结尾
str.replaceAll(regexpression,"");

 String[] stopWords = new String[]{" i ", " a ", " and ", " about ", " an ", " are ", " as ", " at ", " be ", " by ", " com ", " for ", " from ", " how ", " in ", " is ", " it ", " not ", " of ", " on ", " or ", " that ", " the ", " this ", " to ", " was ", " what ", " when ", " where ", " who ", " will ", " with ", " the ", " www "};
        String text = " I would like to do a nice novel about nature AND people ";

        for (String stopword : stopWords) {
            text = text.replaceAll("(?i)"+stopword, " ");
        }
        System.out.println(text);

输出:

 would like do nice novel nature people 

可能有更好的方法。

【讨论】:

  • 1) 不处理方法不区分大小写的要求。 2) 不删除停止words——它会删除“novel”中的“no”。
  • 聪明的把戏,不知道这是可能的。我唯一的批评是replaceAll 确实效率低下,它编译了一次性的正则表达式模式,所以在循环中使用它并不是很好。
【解决方案3】:

这是一个不使用正则表达式的解决方案。我认为它不如我的其他答案,因为它更长且不太清楚,但如果性能真的非常重要,那么这是 O(n) 其中 n 是文本的长度。

Set<String> stopWords = new HashSet<String>();
stopWords.add("a");
stopWords.add("and");
// and so on ...

String sampleText = "I would like to do a nice novel about nature AND people";
StringBuffer clean = new StringBuffer();
int index = 0;

while (index < sampleText.length) {
  // the only word delimiter supported is space, if you want other
  // delimiters you have to do a series of indexOf calls and see which
  // one gives the smallest index, or use regex
  int nextIndex = sampleText.indexOf(" ", index);
  if (nextIndex == -1) {
    nextIndex = sampleText.length - 1;
  }
  String word = sampleText.substring(index, nextIndex);
  if (!stopWords.contains(word.toLowerCase())) {
    clean.append(word);
    if (nextIndex < sampleText.length) {
      // this adds the word delimiter, e.g. the following space
      clean.append(sampleText.substring(nextIndex, nextIndex + 1)); 
    }
  }
  index = nextIndex + 1;
}

System.out.println("Stop words removed: " + clean.toString());

【讨论】:

  • 非常正确,我将break 更改为nextIndex = sampleText.length,应该可以解决这个问题。
  • 哎呀,这实际上是我测试的,但是当我更改代码时我很草率。感谢您指出这一点。
【解决方案4】:

在 whilespace 上拆分 text。然后循环遍历数组并继续附加到 StringBuilder,前提是它不是停用词之一。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 2021-04-06
    • 2013-08-20
    • 2022-11-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多