【问题标题】:Removing stopwords from a String in Java从 Java 中的字符串中删除停用词
【发布时间】:2015-02-25 11:03:07
【问题描述】:

我有一个包含很多单词的字符串,我有一个包含一些停用词的文本文件,我需要从我的字符串中删除这些停用词。 假设我有一个字符串

s="I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs."

删除停用词后,字符串应该是这样的:

"love phone, super fast much cool jelly bean....but recently bugs."

我已经能够做到这一点,但我面临的问题是,当字符串中有相邻的停用词时,它只删除第一个停用词,我得到的结果是:

"love phone, super fast there's much and cool with jelly bean....but recently seen bugs"  

这是我的 stopwordslist.txt 文件: Stopwords

我该如何解决这个问题。这是我到目前为止所做的:

int k=0,i,j;
ArrayList<String> wordsList = new ArrayList<String>();
String sCurrentLine;
String[] stopwords = new String[2000];
try{
        FileReader fr=new FileReader("F:\\stopwordslist.txt");
        BufferedReader br= new BufferedReader(fr);
        while ((sCurrentLine = br.readLine()) != null){
            stopwords[k]=sCurrentLine;
            k++;
        }
        String s="I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs.";
        StringBuilder builder = new StringBuilder(s);
        String[] words = builder.toString().split("\\s");
        for (String word : words){
            wordsList.add(word);
        }
        for(int ii = 0; ii < wordsList.size(); ii++){
            for(int jj = 0; jj < k; jj++){
                if(stopwords[jj].contains(wordsList.get(ii).toLowerCase())){
                    wordsList.remove(ii);
                    break;
                }
             }
        }
        for (String str : wordsList){
            System.out.print(str+" ");
        }   
    }catch(Exception ex){
        System.out.println(ex);
    }

【问题讨论】:

  • 首先拆分字符串会有帮助吗?类似“phrase.split(delims);”的东西您可以在再次缝合之前过滤掉不需要的部分。这可能会解决您的“这个”和“他的”问题。

标签: java string stop-words


【解决方案1】:

最近的一个项目需要在浏览了一些博客和文章后,从给定的文本或文件中过滤停止/词干和脏话的功能。 创建了一个简单的库来过滤数据/文件并在 Maven 中可用。希望这可以帮助一些人。

https://github.com/uttesh/exude

     <dependency>
        <groupId>com.uttesh</groupId>
        <artifactId>exude</artifactId>
        <version>0.0.2</version>
    </dependency>

【讨论】:

  • 这是一个有问题的库
  • @MFARID 你能解释一下它是什么库吗?
【解决方案2】:

似乎你做了一个停止一个停止词被删除一个句子移动到另一个停止词:你需要删除每个句子中的所有停止词。

您应该尝试更改您的代码:

发件人:

for(int ii = 0; ii < wordsList.size(); ii++){
    for(int jj = 0; jj < k; jj++){
        if(stopwords[jj].contains(wordsList.get(ii).toLowerCase())){
            wordsList.remove(ii);
            break;
        }
    }
}

类似于:

for(int ii = 0; ii < wordsList.size(); ii++)
{
    for(int jj = 0; jj < k; jj++)
    {
        if(wordsList.get(ii).toLowerCase().contains(stopwords[jj])
        {
            wordsList.remove(ii);
        }
    }
}

请注意,break 已删除,stopword.contains(word) 更改为 word.contains(stopword)

【讨论】:

    【解决方案3】:

    你可以像这样使用全部替换功能

    String yourString ="I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs."
    yourString=yourString.replaceAll("stop" ,"");
    

    【讨论】:

      【解决方案4】:

      尝试将停用词存储在集合中,然后将您的字符串标记为列表。 之后您可以简单地使用“removeAll”来获得结果。

      Set<String> stopwords = new Set<>()
      //fill in the set with your file
      
      String s="I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs.";
      List<String> listOfStrings = asList(s.split(" "));
      
      listOfStrings.removeAll(stopwords);
      StringUtils.join(listOfStrings, " ");
      

      不需要 for 循环 - 它们通常意味着问题。

      【讨论】:

        【解决方案5】:

        这是一个更优雅的解决方案(恕我直言),仅使用正则表达式:

            // instead of the ".....", add all your stopwords, separated by "|"
            // "\\b" is to account for word boundaries, i.e. not replace "his" in "this"
            // the "\\s?" is to suppress optional trailing white space
            Pattern p = Pattern.compile("\\b(I|this|its.....)\\b\\s?");
            Matcher m = p.matcher("I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs.");
            String s = m.replaceAll("");
            System.out.println(s);
        

        【讨论】:

        • 根本不是break语句的问题。他在第一个循环中接收文本的第一个单词。然后他查看停用词列表(如果存在)。如果他在停用词列表中找到这个词,他就会打破搜索循环。然后他取出下一个单词并在停用词列表中再次搜索。
        • 再次,与其他答案一样,您将删除作为普通单词子串的停用词。
        • @alain.janinm 你是对的,我猜我想太快了。既然你已经提供了正确的答案,我刚刚从我的答案中删除了这个愚蠢的评论。
        • @MichalLozinski 正确,我已更新我的答案以包含单词边界。
        • @geert3 感谢您考虑我的评论;)
        【解决方案6】:

        错误是因为您从迭代的列表中删除了元素。 假设您有包含|word0|word1|word2|wordsList 如果ii 等于1 并且if 测试为真,则调用wordsList.remove(1);。之后您的列表是|word0|word2|。然后ii 递增并等于2,现在它超过了列表的大小,因此word2 永远不会被测试。

        有几种解决方案。例如,您可以将值设置为“”,而不是删除值。或者创建一个特殊的“结果”列表。

        【讨论】:

          【解决方案7】:

          试试下面的程序。

          String s="I love this phone, its super fast and there's so" +
                      " much new and cool things with jelly bean....but of recently I've seen some bugs.";
              String[] words = s.split(" ");
              ArrayList<String> wordsList = new ArrayList<String>();
              Set<String> stopWordsSet = new HashSet<String>();
              stopWordsSet.add("I");
              stopWordsSet.add("THIS");
              stopWordsSet.add("AND");
              stopWordsSet.add("THERE'S");
          
              for(String word : words)
              {
                  String wordCompare = word.toUpperCase();
                  if(!stopWordsSet.contains(wordCompare))
                  {
                      wordsList.add(word);
                  }
              }
          
              for (String str : wordsList){
                  System.out.print(str+" ");
              }
          

          输出: 爱手机,它超级快,有很多新的很酷的东西,果冻豆....但最近我看到了一些错误。

          【讨论】:

          • 不错,不是删除不需要的,而是添加想要的! +1
          【解决方案8】:

          下面试试:

             String s="I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs.";
             String stopWords[]={"love","this","cool"};
             for(int i=0;i<stopWords.length;i++){
                 if(s.contains(stopWords[i])){
                     s=s.replaceAll(stopWords[i]+"\\s+", ""); //note this will remove spaces at the end
                 }
             }
             System.out.println(s);
          

          这样你的最终输出将没有你不想要的单词。只需获取数组中的停用词列表并替换为所需的字符串。
          我的停用词的输出:

          I   phone, its super fast and there's so much new and  things with jelly bean....but of recently I've seen some bugs.
          

          【讨论】:

          • 在for循环之后,s=s.replaceAll("","");将两个空格更改为一个空格?
          • 另外,就像 Vimal 的 aswer 一样,您可以从其他单词的中间删除子字符串(尝试添加“a”作为停用词;))
          【解决方案9】:

          相反,您为什么不使用以下方法。它会更容易阅读和理解:

          for(String word : words){
              s = s.replace(word+"\\s*", "");
          }
          System.out.println(s);//It will print removed word string.
          

          【讨论】:

          • 请注意,此实现将导致两个空格。
          • 这样做的问题是它还会删除其他单词之间的停用词。就像它也从“this”中删除“his”一样。
          • 这也意味着对于大型停用词表,这不是最佳解决方案,因为无论文本有多长,您都会遍历所有内容。尽管如此,如果您的停用词集将保持如此之大,这是最简单的答案之一:)
          • 如果停用词是最后一个词,它会在句尾留下一个空格。
          • 我认为,要解决 cmets 中的问题,您需要以下正则表达式:format("( %s )|(^%s )|( %s$)", word) 比您应该用空格替换匹配项,然后删除所有双空格。仍然有所有的mombo-jumbo,这开始看起来很乱;)
          【解决方案10】:

          尝试使用replaceAll api 之类的字符串:

          String myString = "I love this phone, its super fast and there's so much new and cool things with jelly bean....but of recently I've seen some bugs.";
          String stopWords = "I|its|with|but";
          String afterStopWords = myString.replaceAll("(" + stopWords + ")\\s*", "");
          System.out.println(afterStopWords);
          
          OUTPUT: 
          love this phone, super fast and there's so much new and cool things jelly bean....of recently 've seen some bugs.
          

          【讨论】:

            猜你喜欢
            • 2014-06-06
            • 1970-01-01
            • 2013-12-16
            • 2014-05-22
            • 1970-01-01
            • 2019-12-18
            • 2016-10-06
            • 2015-09-11
            相关资源
            最近更新 更多