这段代码并不完美,当然也效率不高,但是很可能来不及帮助你了,但它确实有效。如果给定一组字符串,它将返回超过一定长度的公共内容。
然而,正如其他人所提到的,算法只能给您一个近似值,因为您可能会遇到一个错误的批次,其中所有产品都具有相同的初始单词,然后代码会意外地将该内容识别为静态。当动态内容与静态内容共享值时,它也可能会产生不匹配,但随着输入的样本大小的增加,出错的可能性将会缩小。
我建议在数据的子集上运行它(20000 行将是一个坏主意!)并进行某种额外的健全性检查(静态元素的最大数量等)
最后的警告:它可能做得很完美,但即使它做到了,你怎么知道哪个项目是PRODUCT哪一个是FREEGIFT?
算法
- 如果集合中的所有字符串都以相同的字符开头,则将该字符添加到“当前匹配”集合中,然后从所有字符串中删除前导字符
- 如果不是,则从第一个字符的所有字符串中删除第一个字符
x
(最小匹配长度)字符不包含在所有其他字符串中
- 一旦出现不匹配(情况 2),如果满足长度要求,则生成当前匹配
- 继续,直到所有字符串都用完
实施情况
private static IEnumerable<string> FindCommonContent(string[] strings, int minimumMatchLength)
{
string sharedContent = "";
while (strings.All(x => x.Length > 0))
{
var item1FirstCharacter = strings[0][0];
if (strings.All(x => x[0] == item1FirstCharacter))
{
sharedContent += item1FirstCharacter;
for (int index = 0; index < strings.Length; index++)
strings[index] = strings[index].Substring(1);
continue;
}
if (sharedContent.Length >= minimumMatchLength)
yield return sharedContent;
sharedContent = "";
// If the first minMatch characters of a string aren't in all the other strings, consume the first character of that string
for (int index = 0; index < strings.Length; index++)
{
string testBlock = strings[index].Substring(0, Math.Min(minimumMatchLength, strings[index].Length));
if (!strings.All(x => x.Contains(testBlock)))
strings[index] = strings[index].Substring(1);
}
}
if (sharedContent.Length >= minimumMatchLength)
yield return sharedContent;
}
Output
设置 1(来自您的示例):
FindCommonContent(strings, 4);
=> "with "
设置 2(来自您的示例):
FindCommonContent(strings, 4);
=> "Brand new ", "and a ", "if you order today"
构建正则表达式
这应该很简单:
"{.*}" + string.Join("{.*}", FindCommonContent(strings, 4)) + "{.*}";
=> "^{.*}Brand new {.*}and a {.*}if you order today{.*}$"
尽管您可以修改算法以返回有关匹配位置的信息(在静态内容之间或之外),但这没问题,因为您知道有些匹配无论如何都会匹配零长度字符串。