C# 使用C从驻留在DB中的字符串集自动生成正则表达式#

C# 使用C从驻留在DB中的字符串集自动生成正则表达式#,c#,regex,C#,Regex,我在数据库中有大约100000个字符串,我想知道是否有办法从这些字符串自动生成正则表达式模式。它们都是字母字符串,使用一组英文字母。例如,不使用(X,W,V)。是否有任何函数或库可以帮助我在C#中实现这一目标?示例字符串是 KHTK 拉兹 给定这两个字符串,我的目标是生成一个正则表达式,它允许像(k,kh,kht,khtk,r,ra,raz)这样的模式不区分大小写。我已经下载并使用了一些有助于生成正则表达式的C#应用程序,但这在我的场景中并不有用,因为我需要一个过程,在这个过程中,我从db中顺序

我在数据库中有大约100000个字符串,我想知道是否有办法从这些字符串自动生成正则表达式模式。它们都是字母字符串,使用一组英文字母。例如,不使用(X,W,V)。是否有任何函数或库可以帮助我在C#中实现这一目标?示例字符串是

KHTK
拉兹

给定这两个字符串,我的目标是生成一个正则表达式,它允许像(k,kh,kht,khtk,r,ra,raz)这样的模式不区分大小写。我已经下载并使用了一些有助于生成正则表达式的C#应用程序,但这在我的场景中并不有用,因为我需要一个过程,在这个过程中,我从db中顺序读取字符串,并向正则表达式添加规则,以便以后可以在应用程序中重用该正则表达式或将其保存在磁盘上

我不熟悉正则表达式模式,不知道我所问的事情是否可能。如果不可能,请向我推荐一些替代方法。

一种简单(有些人可能会说幼稚)的方法是创建一个正则表达式模式,将所有搜索字符串连接在一起,由替代运算符
|
分隔:

  • 对于示例字符串,这将得到
    KHTK | RAZ
  • 为了获得正则表达式捕获前缀,我们将在模式中包括这些前缀,例如
    K | KH | KHT | KHTK | R | RA | RAZ
  • 最后,为了确保这些字符串只捕获整个字符串,而不是作为较大字符串的一部分,我们将分别匹配行首和行尾运算符以及每个字符串的开头和结尾:
    ^K$^KH$^KHT$^KHTK$^R$^RA$^RAZ$
  • 我们希望正则表达式类实现能够完成将长正则表达式模式字符串转换为高效匹配器的繁重工作

    这里的示例程序生成10000个随机字符串,以及一个与这些字符串及其所有前缀完全匹配的正则表达式。然后,程序验证正则表达式是否确实与这些字符串匹配,以及所需的时间

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace ConsoleApplication
    {
        class Program
        {
            private static Random r = new Random();
    
            // Create a string with randomly chosen letters, of a randomly chosen
            // length between the given min and max.
            private static string RandomString(int minLength, int maxLength)
            {
                StringBuilder b = new StringBuilder();
    
                int length = r.Next(minLength, maxLength);
                for (int i = 0; i < length; ++i)
                {
                    b.Append(Convert.ToChar(65 + r.Next(26)));
                }
    
                return b.ToString();
            }
    
            static void Main(string[] args)
            {
                int             stringCount = 10000;                    // number of random strings to generate
                StringBuilder   pattern     = new StringBuilder();      // our regular expression under construction
                HashSet<String> strings     = new HashSet<string>();    // a set of the random strings (and their
                                                                        // prefixes) we created, for verifying the
                                                                        // regex correctness
    
                // generate random strings, track their prefixes in the set,
                // and add their prefixes to our regular expression
                for (int i = 0; i < stringCount; ++i)
                {
                    // make a random string, 2-5 chars long
                    string nextString = RandomString(2, 5);
    
                    // for each prefix of the random string...
                    for (int prefixLength = 1; prefixLength <= nextString.Length; ++prefixLength)
                    {
                        string prefix = nextString.Substring(0, prefixLength);
    
                        // ...add it to both the set and our regular expression pattern
                        if (!strings.Contains(prefix))
                        {
                            strings.Add(prefix);
                            pattern.Append(((pattern.Length > 0) ? "|" : "") + "^" + prefix + "$");
                        }
                    }
                }
    
                // create a regex from the pattern (and time how long that takes)
                DateTime regexCreationStartTime = DateTime.Now;
                Regex r = new Regex(pattern.ToString());
                DateTime regexCreationEndTime = DateTime.Now;
    
                // make sure our regex correcly matches all the strings, and their
                // prefixes (and time how long that takes as well)
                DateTime matchStartTime = DateTime.Now;
                foreach (string s in strings)
                {
                    if (!r.IsMatch(s))
                    {
                        Console.WriteLine("uh oh!");
                    }
                }
                DateTime matchEndTime = DateTime.Now;
    
                // generate some new random strings, and verify that the regex
                // indeed does not match the ones it's not supposed to.
                for (int i = 0; i < 1000; ++i)
                {
                    string s = RandomString(2, 5);
    
                    if (!strings.Contains(s) && r.IsMatch(s))
                    {
                        Console.WriteLine("uh oh!");
                    }
                }
    
                Console.WriteLine("Regex create time: {0} millisec", (regexCreationEndTime - regexCreationStartTime).TotalMilliseconds);
                Console.WriteLine("Average match time: {0} millisec", (matchEndTime - matchStartTime).TotalMilliseconds / stringCount);
    
                Console.ReadLine();
            }
        }
    }
    
    当将字符串数量增加10倍(至100000)时,我得到:

    Regex create time: 288 millisec
    Average match time: 1.25577 millisec
    
    这是较高的,但增长不是线性的


    该应用程序的内存消耗(10000个字符串)从~9MB开始,峰值为~23MB,其中必须包含正则表达式和字符串集,最后降至~16MB(垃圾收集开始了?)从中得出您自己的结论--该程序没有优化以从其他数据结构中挑出正则表达式内存消耗。

    这不是您问题的答案,但既然你提到你是RegEx的新手,我想指出我最近遇到了一个很棒的资源来学习和测试RegEx的感谢Oren,这是一个很大的帮助。我机器上的结果证实了你的。令人惊讶的是,对于长度从1到20个字符不等的140000个字符串,平均匹配时间为.421221毫秒。现在,我将从db中读取字符串,并创建一个类似urs的模式字符串,我将保存在db中,并在每次运行应用程序时重用它。当新字符串添加到数据库中时,模式字符串当然会被更新,这种情况并不常见。请让我知道我是否在正确的轨道上。不幸的是,我没有足够的分数来投票支持你的答案,但我还是很感激这一巨大的帮助。当在数据库中存储模式时,请记住它的大小——它的长度将是已经存在的所有字符串的倍数。如果这是一个问题,您可以使用的选项包括每次重新创建模式,并压缩它。模式应该压缩得很好,因为它几乎由前缀组成;如果需要,请查看System.IO.Compression。谢谢Oren。我过几天再谈
    Regex create time: 288 millisec
    Average match time: 1.25577 millisec