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

标签 c# regex string algorithm text

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

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

例如

Panasonic TV with FREE Blu-Ray Player

Sony TV with FREE DVD Player + Box Office DVD

Kenwood Hi-Fi Unit with $20 Amazon MP3 Voucher

所以这个例子中的格式是:PRODUCT with FREEGIFT

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

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

问题是控制数据馈送的营销机构不断更改静态文本的结构,通常每两周一次,所以这周我可能会:

Brand new Panasonic TV and a FREE Blu-Ray Player if you order today

Brand new Sony TV and a FREE DVD Player + Box Office DVD if you order today

Brand new Kenwood Hi-Fi unit and a $20 Amazon MP3 Voucher if you order today

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

你会如何处理?

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

感谢任何帮助或建议。

最佳答案

此代码并不完美,效率肯定不高,而且很可能来不及帮助您,但它确实有效。如果给定一组字符串,它将返回一定长度以上的公共(public)内容。

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

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

最后的警告:它可能做得很完美,但即使它做到了,你怎么知道哪个是PRODUCT,哪个是FREEGIFT?

算法

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

实现

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;
}

输出

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

尽管您可以修改算法以返回有关匹配位置的信息(在静态内容之间或静态内容之外),但这没问题,因为您知道有些无论如何都会匹配零长度字符串。

关于c# - 动态正则表达式生成,用于数据馈送中可预测的重复字符串模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9020957/

相关文章:

c# - 从 C# 导出 SQL Server 数据库并重新导入

c# - SQL 本地数据库未连接到其他计算机

c++ - 通过传递函数将变量输出为字符串

python将字符串转换为列表

c - C中的memcmp、strcmp和strncmp有什么区别?

c# - 对于 scriptcs `dynamic`,Roslyn 不支持,仅适用于单声道,但单声道在 DLL 上失败

c# - 关于登录凭据

.net - .NET 中的正则表达式 : joining duplicate named captured groups

regex - 删除每行中除某些单词之外的所有内容

java - 将特定网址与正则表达式匹配