通过高效替换600万单词列表中的字符串,从文本中删除个人数据



我试图构建的这个替换函数的性能有问题。从文字帖子中删除个人信息。

我有成千上万的字符串看起来像这样:

嗨,用户: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;

相关内容

  • 没有找到相关文章

最新更新