我试图构建的这个替换函数的性能有问题。从文字帖子中删除个人信息。
我有成千上万的字符串看起来像这样:
嗨,用户:f3a111-010101-01a1-1111是一位很棒的同事。她住在曼彻斯特。如果你想联系她,电话号码是1111111/Marcus
字符串通常是更多的文本。
最后,我想替换单词列表中文本中的所有信息。最后一个字符串将是这样的。
嗨,用户:[userID]是一位出色的同事。她住在[城市]。如果你想联系她,电话号码是[电话]/[名称]
单词列表是小写的,但函数必须不区分大小写。我已经尝试了几种方法,但我跳过了,因为它们太慢了。我现在拥有的是最快的。我使用C#。
这里有一些伪代码来解释它
单词表在字典里。
Dictionary<string, string> word = PopulateWordList();
我用文本循环遍历每个字符串,这些文本可以具有应该替换的值。
foreach (var post in objColl)
{
string[] substrings = Regex.Split(post.Text, @"( |,|!|.)");
replaced = false;
foreach (string str in substrings)
{
if (str.Length >4)
{
stringToCompare = str.ToLower();
if (word.Keys.Contains(stringToCompare))
{
replaced = true;
str = words[stringToCompare];
}
}
}
if (replaced)
post.Text = String.Join("" substrings);
}
此代码有效,但速度较慢。重要的是,如果单词有像.?!这样的尾随字符,就应该匹配。?!或者前面的符号,比如/等等。所有这些符号都不在上面的代码中。
我还尝试过拆分字符串,填充一个哈希集,并确定它们是否与字典键相交。但要做到这一点,你必须在拆分字符串之前先将其小写。然后,当你进行替换时,你必须使用上面的代码来保留大小写。但并没有真正的性能改进,尽管几乎每个职位都有可替换的东西。
在我的实际代码中,我也对每个循环使用并行,但在我的示例中忽略了这一点。
在这段代码之前,我尝试过使用regex replace,它可以处理忽略大小写,但速度非常慢,为了防止拆分半个单词,必须在单词中添加空格和尾随字符。
垃圾代码的小例子:
foreach (var word in wordlist)
{
stringWithText = Regex.Replace(stringWithText, ' ' + word.Oldvalue + ' ', ' ' + word.Newvalue + ' ', RegexOptions.IgnoreCase);
stringWithText = Regex.Replace(stringWithText, ' ' + word.Oldvalue, '.' + word.Newvalue + '.', RegexOptions.IgnoreCase);
stringWithText = Regex.Replace(stringWithText, ' ' + word.Oldvalue, '!' + word.Newvalue + '!', RegexOptions.IgnoreCase);
//And several more replaces to handle every case. You also have to handle when the word is first or last in the string.
}
我尝试了更多的方法,但没有比我的第一个代码更快的了。我广泛讨论了这个话题,这些年来有很多关于这个话题的线索。我看了很多,但没有找到更好的方法。
我使用StopWatch来衡量浏览同样小的帖子和单词列表所需的时间,这样我就知道每次代码更改所需的花费。
关于如何改进这一点,或者是否有完全不同的方法来解决这一问题,有什么想法吗?只是不要建议用人工智能语言模型将数据发送到云API来解决这个问题,因为它包含个人数据。
也有可能不在单词列表中的变位问题,或者如果你有像";曼城";。这将被替换为";[城市]城市;所以我的代码不处理有空格的单词。
我也知道我不可能完美地解决这个问题,但它可能会做得更好更快。
此部分尤其是次优部分。
if (word.Keys.Contains(stringToCompare))
{
replaced = true;
str = words[stringToCompare];
}
更改PopulateWordList(),以便在执行new Dictionary<string, string>()
时使用允许比较器的构造函数,如下所示:new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
。
然后更改:
stringToCompare = str.ToLower();
if (word.Keys.Contains(stringToCompare))
{
replaced = true;
str = words[stringToCompare];
}
至:
if (word.TryGetValue(str, out temp))
{
replaced = true;
str = temp;
}
就在前臂外侧之前,做一个string temp = null;