2014-07-09 1 views
3

Je crée un log4net appender qui génère NHibernate scripts SQL prêts à être exécutés.Regex Remplacer les captures répétées

Je souhaite utiliser Regex pour remplacer la sortie de log4net par un script prêt à l'emploi.
Une entrée de l'échantillon serait

command 5:UPDATE [PlanParameter] SET Mode = @p0, DefaultValueString = @p1, ParameterID = @p2 WHERE ID = @p3;@p0 = 1 [Type: Int16 (0)], @p1 = '0' [Type: String (4000)], @p2 = 2 [Type: Int32 (0)], @p3 = 1362 [Type: Int32 (0)] 

Ce que je veux remplacer par

UPDATE [PlanParameter] SET Mode = 1, DefaultValueString = '0', ParameterID = 2 WHERE ID = 1362 

J'ai créé le Regex suivant:

command \d+:(?<Query>(?:(?<PreText>[\w\s\[\]]+ =)(@p\d+)(?<PostText>,?))+);(?<Parameters>(?:@p\d+ = ('?\w+'?) \[Type: \w+ \(\d+\)\],? ?)+) 

qui correspond et capture parfaitement mes échantillons:

Expresso matches output

Je voulais que l'ensemble du remplacement soit géré par le moteur Regex. Je pensais que je peux utiliser une chaîne de remplacement comme celle-ci:

${PreText}$2${PostText} 

mais que les rendements que la dernière capture, et non mon objectif final.

En attendant, je l'ai utilisé C# pour y arriver:

Regex reg = new Regex(@"command \d+:(?<Query>(?:(?<PreText>[\w\s\[\]]+ =)(@p\d+)(?<PostText>,?))+);(?<Parameters>(?:@p\d+ = ('?\w+'?) \[Type: \w+ \(\d+\)\],? ?)+)", RegexOptions.Compiled); 
    string sample = @"command 5:UPDATE [PlanParameter] SET Mode = @p0, DefaultValueString = @p1, ParameterID = @p2 WHERE ID = @p3;@p0 = 1 [Type: Int16 (0)], @p1 = '0' [Type: String (4000)], @p2 = 2 [Type: Int32 (0)], @p3 = 1362 [Type: Int32 (0)]"; 
    Match match = reg.Match(sample); 
    string result = match.Groups["Query"].Value; 
    for (int i = 0; i < match.Groups[1].Captures.Count; i++) 
    { 
     Capture capture = match.Groups[1].Captures[i]; 
     result = result.Replace(capture.Value, match.Groups[2].Captures[i].Value); 
    } 

Cela fonctionne parfaitement, mais je suis sûr qu'il ya une façon plus propre et soignée de faire cela. Peut-être avec une expression Regex différente peut-être?

Toute aide serait appréciée.

+1

+1 pour expérimenter avec CaptureCollection :) – zx81

Répondre

1

Voici une approche regex plus compacte:

Recherche: = (@p\d+)(?=.*?\1 (= [^\[]+))|;(?!.*= @p\d).*

Remplacer: ${2}

Cela remplace tous les paramètres avec leurs valeurs et efface la fin de la chaîne.

Voir le volet Substitution au bas du regex demo.

sortie:

command 5:UPDATE [PlanParameter] SET Mode = 1 , DefaultValueString = '0' , ParameterID = 2 WHERE ID = 1362 

échantillon C#

String replaced = Regex.Replace(yourString, @"= (@p\d+)(?=.*?\1 (= [^\[]+))|;(?!.*= @p\d).*", "${2}"); 

Explication

  • Les parenthèses dans (@p\d+) captu re @p et chiffres au groupe 1
  • Le (?=.*?\1 (= [^\[]+)) affirme que préanalyse ce qui suit est ...
  • .*? match de CARactère jusqu'à ...
  • \1 ce qui a été adapté par le groupe 1 (par exemple @p0)
  • Les parenthèses dans (= [^\[]+)) capture au groupe 2 du = littéral, tous les caractères qui ne sont pas un [ (que nous utilisons comme séparateur pour savoir quand votre valeur se termine. Ceci est votre valeur
  • OU ... | nous vous offrons aussi la fin de la chaîne, et puisqu'il n'y a pas de groupe 2 lorsqu'il est adapté, le remplacement ${2} sera Nix il
  • ; point-virgule
  • Pour la sécurité, le préanalyse négative (?!.*= @p\d) affirme que ce qui suit est pas CARactère puis = @p + chiffres
  • .* correspond à un point-virgule et tous les caractères à la fin de la chaîne
  • La chaîne de remplacement ${2} est = et le groupe 2 (la valeur)

Référence

+1

Toda Raba, heureux il a aidé. :) – zx81

+0

Wow merci, exactement ce que je cherchais! Je suis tout à fait un novice avec Regex et j'étudierai les vôtres avec soin :) –

+0

Hehe Je commence à regretter de ne pas pouvoir m'envoyer plus d'une fois .. –

Questions connexes