Hello!

On MSDN I found the regular expression that suits me best. But trying to tune it for themselves, faced with the problem that it begins to produce unexpected results.

An example below. It is necessary to snatch from the text fragment {mno ...} there may be an unlimited number of attachments inside.

$content = "{abc}{mno{xyz}}" $mask = "[^{}]*" + "(" + "((?'Open'\{)[^{}]*)+" + "((?'Close-Open'\})[^{}]*)+" + ")*" + "(?(Open)(?!))" $date = [Datetime]::Now $match = [Regex]::Match($content, $mask) if ($match.Success) { $grp = 0 $match.Groups | %{ ("Group {0} : {1}" -f $grp++, $_.Value) $cap = 0 $_.Captures | %{ ("`tCapture {0}: {1}" -f $cap++, $_.Value) } } } ([Datetime]::Now - $date).ToString("hh\:mm\:ss") #Group 0 : {abc}{mno{xyz}} # Capture 0: {abc}{mno{xyz}} #Group 1 : {mno{xyz}} # Capture 0: {abc} # Capture 1: {mno{xyz}} #Group 2 : {xyz # Capture 0: {abc # Capture 1: {mno # Capture 2: {xyz #Group 3 : } # Capture 0: } # Capture 1: } # Capture 2: } #Group 4 : #Group 5 : mno{xyz} # Capture 0: abc # Capture 1: xyz # Capture 2: mno{xyz} 

I tried to change the mask

  $mask = "[^{}]*" + "(" + "((?'Open'\{)mno[^{}]*)+" + "((?'Close-Open'\})[^{}]*)+" + ")*" + "(?(Open)(?!))" 

but it turns out all garbage

  • Here such an expression should be: $mask = "[^{}]+{((?>[^{}]+|{(?<c>)|}(?<-c>))*(?(c)(?!)))}" - Wiktor Stribiżew
  • @stribizhev, Something is wrong here with brackets ... It seems {} shielded, but it swears at all ... - Pincher1519
  • I don’t need to screen anything, Group 0 : mno{xyz}// Capture 0: mno{xyz}// Group 1 : xyz// Capture 0: xyz// Group 2 : - Wiktor Stribiżew
  • one
    And what result do you need? - Wiktor Stribiżew
  • @stribizhev, you need to snatch the result from {mno to} related to it. the fact is that there may be several investments and several such groups can meet ... - Pincher1519

1 answer 1

The current regular expression contains a sub-pattern (((?'Open'\{)[^{}]*)+((?'Close-Open'\})[^{}]*)+)*(?(Open)(?!)) , in which there are 3 non-nominal and 2 nominal fascinating subtitles:

 ( # 1-ая неименная подмаска ( # 2-ая неименная подмаска (?'Open'\{) # 1-ая именная подмаска [^{}]* )+ ( # 3-ая неименная подмаска (?'Close-Open'\}) # 2-ая именная подмаска [^{}]* )+ )* (?(Open)(?!)) 

Therefore, the result is 5 groups.

If you need to get only the text in the second substring in curly brackets, you can use the following regular expression and code:

 $content = "{abc}{mno{xy{z}}}" $mask = "(?<!^){((?>[^{}]+|{(?<c>)|}(?<-c>))*(?(c)(?!)))}" $match = [Regex]::Match($content, $mask) if ($match.Success) {$match.Groups[1].Value} 

Result: mno{xy{z}} (with the input line {abc}{mno{xy{z}}} )

Regular expression demo

In a regular expression (?<!^) , A preliminary preview block that provides a match within a line, not at its beginning, but {((?>[^{}]+|{(?<c>)|}(?<-c>))*(?(c)(?!)))} finds the substring from the first opening brace to the corresponding closing brace.