2 votes

Regex avec groupes d'équilibrage

J'ai besoin d'écrire des regex qui capturent des arguments génériques (qui peuvent aussi être génériques) de type nom en notation spéciale comme ceci :

System.Action[Int32,Dictionary[Int32,Int32],Int32]

supposons que le nom du type est [\w.]+ et le paramètre est [\w.,\[\]]+ donc j'ai besoin de prendre seulement Int32 , Dictionary[Int32,Int32] y Int32

En fait, je dois prendre quelque chose si la pile de groupes d'équilibrage est vide, mais je ne comprends pas vraiment comment.

UPD

La réponse ci-dessous m'a permis de résoudre le problème rapidement (mais sans validation appropriée et avec une limitation de la profondeur = 1), mais j'ai réussi à le faire avec l'équilibrage des groupes :

^[\w.]+                                              #Type name
\[(?<delim>)                                         #Opening bracet and first delimiter
[\w.]+                                               #Minimal content
(
[\w.]+                                                       
((?(open)|(?<param-delim>)),(?(open)|(?<delim>)))*   #Cutting param if balanced before comma and placing delimiter
((?<open>\[))*                                       #Counting [
((?<-open>\]))*                                      #Counting ]
)*
(?(open)|(?<param-delim>))\]                         #Cutting last param if balanced
(?(open)(?!)                                         #Checking balance
)$

Démo)((%3f%3copen%3e%5c%5b))((%3f%3c-open%3e%5c%5d)))%5c%5d(%3f(open)%7c(%3f%3cparam-delim%3e)(%3f%3cdelim%3e))%24&i=Action%5bInt%2cBool%2cDictionary%5bInt%2cbool%5d%5d)

UPD2 (Dernière optimisation)

^[\w.]+
\[(?<delim>)
[\w.]+
(?:
 (?:(?(open)|(?<param-delim>)),(?(open)|(?<delim>))[\w.]+)?
 (?:(?<open>\[)[\w.]+)?
 (?:(?<-open>\]))*
)*
(?(open)|(?<param-delim>))\]
(?(open)(?!)
)$

2voto

Wiktor Stribiżew Points 100073

Je propose capturer ces valeurs en utilisant

\w+(?:\.\w+)*\[(?:,?(?<res>\w+(?:\[[^][]*])?))*

Voir le Démonstration de regex)%2A&i=System.Action%5BInt32%2CDictionary%5BInt32%2CInt32%5D%2CInt32%5D%0D%0A) .

Détails :

  • \w+(?:\.\w+)* - correspond aux caractères de 1+ mots suivis de . + 1+ chars de mots 1 ou plusieurs fois
  • \[ - un littéral [
  • (?:,?(?<res>\w+(?:\[[^][]*])?))* - 0 ou plusieurs séquences de :
    • ,? - une virgule facultative
    • (?<res>\w+(?:\[[^][]*])?) - Capture du groupe "res" :
      • \w+ - un ou plusieurs caractères de mot (vous souhaitez peut-être [\w.]+ )
      • (?:\[[^][]*])? - 1 ou 0 (changement ? a * pour correspondre à 1 ou plusieurs) séquences d'un [ , 0+ caractères autres que [ y ] et une fermeture ] .

A Démonstration C# ci-dessous :

var line = "System.Action[Int32,Dictionary[Int32,Int32],Int32]";
var pattern = @"\w+(?:\.\w+)*\[(?:,?(?<res>\w+(?:\[[^][]*])?))*";
var result = Regex.Matches(line, pattern)
        .Cast<Match>()
        .SelectMany(x => x.Groups["res"].Captures.Cast<Capture>()
            .Select(t => t.Value))
        .ToList();
foreach (var s in result) // DEMO
    Console.WriteLine(s);

UPDATE : Pour tenir compte d'une profondeur inconnue [...] les sous-chaînes, utilisez

\w+(?:\.\w+)*\[(?:\s*,?\s*(?<res>\w+(?:\[(?>[^][]+|(?<o>\[)|(?<-o>]))*(?(o)(?!))])?))*

Voir le Démonstration de regex(%3F(o)(%3F!))%5D)%3F))&i=System.Action%5BInt32%2CDictionary%5BInt32%2CDictionary%5BInt32%2CInt32%5D%5D%2CInt32%5D%0D%0A)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X