2010-05-28 3 views
0

J'ai environ 100 000 chaînes dans la base de données et je veux s'il y a un moyen de générer automatiquement un modèle regex à partir de ces chaînes. Tous sont des chaînes alphabétiques et utilisent un ensemble d'alphabets de lettres anglaises. (X, W, V) n'est pas utilisé par exemple. Y at-il une fonction ou une bibliothèque qui peut m'aider à atteindre cette cible en C#? chaînes Exemple sontGénérer automatiquement Regex à partir d'un ensemble de chaînes résidant dans la base de données en utilisant C#

KHTK
Raz

Compte tenu de ces deux chaînes mon objectif est de générer une expression régulière qui permet à des modèles comme (k, kh, kht, khtk, r, ra, Raz) insensible à la casse bien sûr. J'ai téléchargé et utilisé certaines applications C# qui aident à générer une regex mais cela n'est pas utile dans mon scénario car je veux un processus dans lequel je lis séquentiellement les chaînes de db et ajoute des règles à regex afin que cette expression puisse être réutilisée plus tard dans l'application ou enregistré sur le disque.

Je suis nouveau sur les modèles regex et je ne sais pas si la chose que je demande est même possible ou non. Si ce n'est pas possible, veuillez me suggérer une autre approche.

+0

Ce n'est pas une réponse à votre question, mais puisque vous mentionnez que vous êtes nouveau à RegEx, je voudrais signaler une excellente ressource que j'ai récemment trouvée pour apprendre et tester le http://gskinner.com/RegExr de RegEx/ –

Répondre

2

Un simple (certains pourraient dire naïf) approche serait de créer un modèle de regex qui concaténer toutes les chaînes de recherche, séparés par l'opérateur alternance |:

  1. Pour vos chaînes par exemple, que diriez-vous obtenir KHTK|RAZ .
  2. Pour avoir les préfixes de capture regex, nous incluons ces préfixes dans le motif, par ex. K|KH|KHT|KHTK|R|RA|RAZ. Enfin, pour nous assurer que ces chaînes sont capturées uniquement en entier et non en tant que partie de chaînes plus grandes, nous allons faire correspondre les opérateurs de début et de fin de ligne ainsi que le début et la fin de chaque chaîne. , respectivement: ^K$|^KH$|^KHT$|^KHTK$|^R$|^RA$|^RAZ$

Nous nous attendons à ce que l'implémentation de la classe Regex effectue la lourde tâche de conversion de la longue chaîne de motifs regex en un matcher efficace.

Le programme exemple génère ici 10 000 chaînes aléatoires et une expression régulière correspondant exactement à ces chaînes et à tous leurs préfixes. Le programme vérifie ensuite que la regex correspond bien à ces chaînes, et combien de temps cela prend.

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

Sur une boîte Intel Core2 Je reçois les chiffres suivants pour 10.000 cordes:

Regex create time: 46 millisec 
Average match time: 0.3222 millisec 

En augmentant le nombre de chaînes de 10 fois (à 100 000), je reçois:

Regex create time: 288 millisec 
Average match time: 1.25577 millisec 

Ceci est plus élevé, mais la croissance est inférieure à linéaire. La consommation de mémoire de l'application (10 000 chaînes) a commencé à ~ 9 Mo, a atteint un sommet de ~ 23 Mo qui devait contenir à la fois la regex et l'ensemble de chaînes et a chuté à ~ 16 Mo vers la fin. vos propres conclusions à partir de cela - le programme n'optimise pas pour taquiner la consommation de mémoire regex des autres structures de données.

+0

Merci Oren c'était une aide précieuse.Les résultats sur ma machine confirment les vôtres. Étonnamment, le temps de correspondance moyen est de .421221 millisec pour 140000 chaînes dont la longueur varie de 1 à 20 caractères. Maintenant, je vais lire mes chaînes de DB et créer une chaîne de modèle comme urs que je vais enregistrer en DB et réutilisera chaque fois que je cours mon application. La chaîne de modèle sera bien sûr mise à jour lorsque de nouvelles chaînes sont ajoutées dans la base de données et ce n'est pas un cas fréquent. SVP laissez-moi savoir si je suis sur la bonne voie. Malheureusement, je n'ai pas assez de points pour voter, mais j'apprécie quand même cette aide. –

+0

Lorsque vous stockez le motif dans la base de données, gardez à l'esprit sa taille - sa longueur va être un multiple de toutes les chaînes qui étaient déjà là. Si c'est un problème, les options dont vous disposez sont notamment de recréer le motif à chaque fois et de le compresser. Le motif devrait bien se comprimer, car il est composé de préfixes; regardez la System.IO.Compression si nécessaire. –

+0

Merci Oren. j'y reviendrai dans quelques jours –

Questions connexes