8

我想知道如何从字符串中替换(删除)多个单词(如 500+)。我知道我可以使用 replace 函数对单个单词执行此操作,但如果我想替换 500 多个单词怎么办?我有兴趣从文章中删除所有通用关键字(例如“and”、“I”、“you”等)。

这是 1 次替换的代码。我想做 500+ 次。

        string a = "why and you it";
        string b = a.Replace("why", "");
        MessageBox.Show(b);

谢谢

@Sergey Kucher 文本大小从几百字到几千字不等。我正在从随机文章中替换这些词。

4

6 回答 6

8

我通常会做类似的事情:

// If you want the search/replace to be case sensitive, remove the 
// StringComparer.OrdinalIgnoreCase
Dictionary<string, string> replaces = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { 
    // The format is word to be searched, word that should replace it
    // or String.Empty to simply remove the offending word
    { "why", "xxx" }, 
    { "you", "yyy" },
};

void Main()
{
    string a = "why and you it and You it";

    // This will search for blocks of letters and numbers (abc/abcd/ab1234)
    // and pass it to the replacer
    string b = Regex.Replace(a, @"\w+", Replacer);
}

string Replacer(Match m)
{
    string found = m.ToString();

    string replace;

    // If the word found is in the dictionary then it's placed in the 
    // replace variable by the TryGetValue
    if (!replaces.TryGetValue(found, out replace))
    {
        // otherwise replace the word with the same word (so do nothing)
        replace = found;
    }
    else
    {
        // The word is in the dictionary. replace now contains the
        // word that will substitute it.

        // At this point you could add some code to maintain upper/lower 
        // case between the words (so that if you -> xxx then You becomes Xxx
        // and YOU becomes XXX)
    }

    return replace;
}

正如其他人所写,但子字符串没有问题(ass原则......您不想ass从 cl es 中删除asses :-)),并且仅在您只需要删除单词时才起作用:

var escapedStrings = yourReplaces.Select(Regex.Escape);
string result = Regex.Replace(yourInput, @"\b(" + string.Join("|", escapedStrings) + @")\b", string.Empty);

我使用\b单词边界...解释它是什么有点复杂,但是找到单词边界很有用:-)

于 2013-08-04T06:45:51.333 回答
0

当然取决于情况,
但是如果您的文本很长并且单词很多,
并且您想要优化性能。

您应该从单词中构建一个 trie,并在 Trie 中搜索匹配项。

它不会降低复杂度的顺序,仍然是 O(nm),但是对于大量的单词,它将能够针对每个字符检查多个单词,而不是一个一个地检查。
我可以假设几个百字应该足以让这个更快。

这是我认为最快的方法,我
为您编写了一个函数:

public struct FindRecord
    {
        public int WordIndex;
        public int PositionInString;
    }

    public static FindRecord[] FindAll(string input, string[] words)
    {
        LinkedList<FindRecord> result = new LinkedList<FindRecord>();
        int[] matchs = new int[words.Length];

        for (int i = 0; i < input.Length; i++)
        {
            for (int j = 0; j < words.Length; j++)
            {
                if (input[i] == words[j][matchs[j]])
                {
                    matchs[j]++;
                    if(matchs[j] == words[j].Length)
                    {
                        FindRecord findRecord = new FindRecord {WordIndex = j, PositionInString = i - matchs[j] + 1};
                        result.AddLast(findRecord);
                        matchs[j] = 0;
                    }

                }
                else
                    matchs[j] = 0;
            }
        }
        return result.ToArray();
    }

另一种选择:
在极少数情况下,正则表达式会比构建代码更快。

尝试使用

public static string ReplaceAll(string input, string[] words)
    {
        string wordlist = string.Join("|", words);
        Regex rx = new Regex(wordlist, RegexOptions.Compiled);
        return rx.Replace(input, m => "");
    }
于 2013-08-04T07:34:50.403 回答
0

尝试这个:

string text = "word1 word2 you it";
List<string> words = new System.Collections.Generic.List<string>();
words.Add("word1");
words.Add("word2");
words.ForEach(w => text = text.Replace(w, ""));

编辑

如果你想用另一个文本替换文本,你可以创建类Word

 public class Word
 {
     public string SearchWord { get; set; }
     public string ReplaceWord { get; set; }
 }

并将上面的代码更改为:

string text = "word1 word2 you it";
List<Word> words = new System.Collections.Generic.List<Word>();
words.Add(new Word() { SearchWord = "word1", ReplaceWord = "replaced" });
words.Add(new Word() { SearchWord = "word2", ReplaceWord = "replaced" });
words.ForEach(w => text = text.Replace(w.SearchWord, w.ReplaceWord));
于 2013-08-04T06:45:38.643 回答
0

如果您谈论的是单个字符串,则解决方案是通过简单的替换方法将它们全部删除。如您所见:

“返回一个新字符串,其中当前实例中出现的所有指定字符串都替换为另一个指定字符串”。

您可能需要替换几个单词,您可以列出这些单词:

List<string> wordsToRemove = new List<string>();
wordsToRemove.Add("why");
wordsToRemove.Add("how);

等等

然后将它们从字符串中删除

foreach(string curr in wordsToRemove)
   a = a.ToLower().Replace(curr, "");

重要的

如果你想保持你的字符串原样,不降低单词并且不为大小写使用而苦苦挣扎

foreach(string curr in wordsToRemove)
   // You can reuse this object
   Regex regex = new Regex(curr, RegexOptions.IgnoreCase);
   myString = regex.Replace(myString, "");
于 2013-08-04T06:46:13.190 回答
0

创建您想要的所有文本的列表并将其加载到列表中,您可以非常简单或变得非常复杂。一个简单的例子是:

var sentence = "mysentence hi";
var words = File.ReadAllText("pathtowordlist.txt").Split(Enviornment.NewLine);
foreach(word in words)
   sentence.replace("word", "x");

如果您想要双重映射方案,您可以创建两个列表。

于 2013-08-04T06:39:05.613 回答
0

正则表达式可以做得更好,你只需要一个列表中的所有替换词,然后:

var escapedStrings = yourReplaces.Select(PadAndEscape);
string result = Regex.Replace(yourInput, string.Join("|", escapedStrings);

这需要一个在转义字符串之前对字符串进行空格填充的函数:

public string PadAndEscape(string s)
{
    return Regex.Escape(" " + s + " ");
}
于 2013-08-04T09:17:41.463 回答