动态正则表达式生成,用于数据馈送中可预测的重复字符串模式

我目前正在尝试处理一些我无法控制的数据源,我在C#中使用正则表达式来提取信息。

数据馈送的发起者从其数据库中提取基本行数据(如产品名称,价格等),然后在英文文本行中格式化该数据。 对于每一行,一些文本是重复的静态文本,一些是从数据库中动态生成的文本。

例如

松下电视免费蓝光播放器

索尼电视免费DVD播放机+票房DVD

Kenwood Hi-Fi部门提供20美元的亚马逊MP3优惠券

因此,此实例中的格式为:带有FREEGIFT的 PRODUCT

PRODUCTFREEGIFT是每行的动态部分,“with”文本是静态的。 每个Feed有大约2000行。

创建正则表达式以提取动态部分是微不足道的。

问题在于,控制数据源的营销方式一直在改变静态文本的结构,通常是两周一次,所以本周我可能会:

如果您今天订购,全新松下电视和免费蓝光播放器

如果您今天订购,全新索尼电视和免费DVD播放机+票房DVD

如果您今天订购,全新的Kenwood Hi-Fi装置和20美元的亚马逊MP3优惠券

下周它可能会有所不同,所以我必须继续修改我的正则表达式……

你会怎么处理这个?

是否有算法来确定重复的字符串行中的静态和可变文本? 如果是这样,那么使用这种算法的输出以编程方式创建动态正则表达式的最佳方法是什么?

感谢您的帮助或建议。

这段代码并不完美,它肯定效率不高,而且很可能为时已晚,无法帮助您,但它确实有效。 如果给定一组字符串,它将返回超过一定长度的公共内容。

但是,正如其他人所提到的,算法只能给你一个近似值,因为你可能会遇到一个错误的批处理,其中所有产品都有相同的初始词,然后代码会意外地将该内容识别为静态。 当动态内容与静态内容共享值时,它也可能产生不匹配,但随着您加入其中的样本的大小增加,错误的可能性将缩小。

我建议在你的数据子集上运行这个(20000行是个坏主意!),并进行某种额外的健全性检查(最多静态元素数量等)

最后的警告:它可能做得很完美,但即使有,你怎么知道哪个项目是产品 ,哪个是FREEGIFT

算法

  1. 如果集合中的所有字符串都以相同的字符开头,请将该字符添加到“当前匹配”集中,然后从所有字符串中删除前导字符
  2. 如果不是,则从所有其他字符串中不包含第一个x (最小匹配长度)字符的字符串中删除第一个字符
  3. 一旦达到不匹配(情况2),如果满足长度要求,则产生当前匹配
  4. 继续,直到所有字符串都用尽

实施

 private static IEnumerable 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; } 

产量

设置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{.*}$" 

虽然您可以修改算法以返回有关匹配位置(静态内容之间或之外)的信息,但这很好,因为您知道有些匹配零长度字符串。

我认为使用算法是可能的,但是编写它的时间与简单地执行正则表达式可能不值得。

但是,您可以更快地完成更改过程。 如果不是在应用程序中使用Regex String,而是将其放在某个文本文件中,每次更改时都不必重新编译和重新部署所有内容,只需编辑文本文件即可。

根据您的项目规模和实施情况,这可以为您节省大量时间。