从文本C#中删除停用词

时间:2012-05-04 11:31:02

标签: c#

我想从输入字符串中删除一系列停用词,我有以下过程

string[] arrToCheck = new string[] { "try ", "yourself", "before " };

string input = "Did you try this yourself before asking";
foreach (string word in arrToCheck )
{
input = input.Replace(word, "");
}

这是执行此任务的最佳方式,特别是当我有(450)停用单词且输入字符串很长时?我更喜欢使用替换方法,因为我想在它们以不同的形态出现时删除停用词。例如,如果停用词是“do”,则从(do,do等)中删除“do”。有没有更好,最快的处理建议?提前谢谢。

6 个答案:

答案 0 :(得分:4)

我可以建议StringBuilder吗?

http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx

string[] arrToCheck = new string[] { "try ", "yourself", "before " };

StringBuilder input = new StringBuilder("Did you try this yourself before asking");
foreach (string word in arrToCheck )
{
    input.Replace(word, "");
}

因为它在自己的数据结构中进行了所有处理,并且没有分配数百个新字符串,我相信你会发现它的内存效率更高。

答案 1 :(得分:3)

这方面有几个方面

过早优化
给出的方法有效且易于理解/维护。是否会导致性能问题? 如果没有,那就不用担心了。如果它引起了问题,那就看看吧。

预期结果
在示例中,您希望输出是什么?

"Did you this asking"

"Did you  this   asking"

你已经在“try”和“before”结束时添加了空格,但没有添加“自己”。为什么?错字?

string.Replace()区分大小写。如果您关心套管,则需要修改代码。

使用部分内容很麻烦 单词在不同时态发生变化。 “做”的例子被从“做”的话中删除了,但是如何“接受”和“接受”? 停止词的顺序很重要,因为您正在更改输入。有可能(我不知道有多可能但可能)在更改之后输入中没有出现的单词“出现”。你想每次回去重新检查吗?

你真的需要删除部分内容吗?

<强>优化
当前方法将通过输入字符串n次,其中n是要编辑的字数,每次发生替换时都会创建一个新字符串。这个 慢。

使用 StringBuilder (上面的akatakritos)会加快这个速度,所以我先尝试一下。重新测试,看看这是否足够快。

可以使用Linq

编辑
只是按''来展示。您还需要允许标点符号并决定它们应该发生什么 结束编辑

[TestMethod]
public void RedactTextLinqNoPartials() {

    var arrToCheck = new string[] { "try", "yourself", "before" };
    var input = "Did you try this yourself before asking";

    var output = string.Join(" ",input.Split(' ').Where(wrd => !arrToCheck.Contains(wrd)));

    Assert.AreEqual("Did you this asking", output);

}

将删除所有整个单词(和空格。不可能看到删除单词的位置)但没有一些基准测试我不会说它更快。

使用linq处理部分内容会变得混乱但如果我们只想要一次通过(不检查'发现的'单词')就可以工作

[TestMethod]
public void RedactTextLinqPartials() {

    var arrToCheck = new string[] { "try", "yourself", "before", "ask" };
    var input = "Did you try this yourself before asking";

    var output = string.Join(" ", input.Split(' ').Select(wrd => {
        var found = arrToCheck.FirstOrDefault(chk => wrd.IndexOf(chk) != -1);
            return found != null
                   ? wrd.Replace(found,"")
                   : wrd;
    }).Where(wrd => wrd != ""));


    Assert.AreEqual("Did you this ing", output);

}

只是从看这个我会说它比string.Replace()慢,但没有一些数字,没有办法告诉。这肯定更复杂。

底线
String.Replace()方法(修改为使用字符串构建器并且不区分大小写)看起来像是一个很好的第一个解决方案。在尝试任何更复杂的事情之前,我会在可能的性能条件下对其进

hth,
艾伦。

答案 2 :(得分:1)

要想从句子中删除字符串列表并将结果汇​​总回来的简单方法,您可以执行以下操作:

var input = "Did you try this yourself before asking"; 
var arrToCheck = new [] { "try ", "yourself", "before " };
var result = input.Split(arrToCheck, 
                         arrToCheck.Count(), 
                         StringSplitOptions.None)
                  .Aggregate((first, second) => first + second);

这将使用单词分隔符将原始字符串分开,并使用split数组中的结果集创建一个最终字符串。

结果为"Did you this before asking"

答案 3 :(得分:0)

缩短您的代码,并使用LINQ

string[] arrToCheck = new string[] { "try ", "yourself", "before " };   
var test = new StringBuilder("Did you try this yourself before asking"); 

arrToCheck.ForEach(x=> test = test.Replace(x, "")); 

Console.Writeln(test.ToString());

答案 4 :(得分:0)

String.Join(" ",input.
          Split(' ').Where(w=>stop.Where(sW=>sW==w).
                   FirstOrDefault()==null).ToArray());

答案 5 :(得分:0)

你走了:

var words_to_remove = new HashSet<string> { "try", "yourself", "before" };
string input = "Did you try this yourself before asking";

string output = string.Join(
    " ",
    input
        .Split(new[] { ' ', '\t', '\n', '\r' /* etc... */ })
        .Where(word => !words_to_remove.Contains(word))
);

Console.WriteLine(output);

打印:

Did you this asking

HashSet提供了非常快速的查找,因此words_to_remove中的450个元素应该没有任何问题。此外,我们只遍历输入字符串一次(而不是每个字一次删除,如示例所示)。

但是,如果输入字符串非常长,有一些方法可以通过不将拆分结果一次性保存在内存中来提高内存效率(如果不是更快)。

要删除“do”而不是“do”,“do”等...您必须在words_to_remove中包含所有这些变体。如果你想以一般方式删除前缀,那么可以(相对)有效地使用trie个词来删除(或者输入字符串的suffix tree),但是该做什么呢?当“do”是应该删除的东西的前缀,例如“did”?或者当它是不应该被移除的东西的前缀时,例如“dog”?

顺便说一句,要删除单词,无论他们的情况如何,只需将适当的不区分大小写的比较器传递给HashSet构造函数,例如StringComparer.CurrentCultureIgnoreCase

---编辑---

这是另一种选择:

var words_to_remove = new[] { " ", "try", "yourself", "before" }; // Note the space!
string input = "Did you try this yourself before asking";

string output = string.Join(
    " ",
    input.Split(words_to_remove, StringSplitOptions.RemoveEmptyEntries)
);

我猜它应该更慢(除非string.Split在内部使用哈希表),但是很好又整洁;)