Makla
Makla

Reputation: 10459

c# regex matches exclude first and last character

I know nothing about regex so I am asking this great community to help me out. With the help of SO I manage to write this regex:

    string input = "((isoCode=s)||(isoCode=a))&&(title=s)&&((ti=2)&&(t=2))||(t=2&&e>5)";
    string pattern = @"\((?>\((?<DEPTH>)|\)(?<-DEPTH>)|.?)*(?(DEPTH)(?!))\)|&&|\|\|";
    MatchCollection matches = Regex.Matches(input, pattern);
    foreach (Match match in matches)
    {
        Console.WriteLine(match.Groups[0].Value);
    }

And the result is:

((isoCode=s)||(isoCode=a))
&&
(title=s)
&&
((ti=2)&&(t=2))
||
(t=2&&e>5)

but I need result like this (without first/last "(", ")"):

(isoCode=s)||(isoCode=a)
&&
title=s
&&
(ti=2)&&(t=2)
||
t=2&&e>5

Can it be done? I know I can do it with substring (removing first and last character), but I want to know if it can be done with regex.

Upvotes: 1

Views: 761

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626826

You may use

\((?<R>(?>\((?<DEPTH>)|\)(?<-DEPTH>)|[^()]+)*(?(DEPTH)(?!)))\)|(?<R>&&|\|\|)

See the regex demo, grab Group "R" value.

Details

  • \( - an open (
  • (?<R> - start of the R named group:
    • (?> - start of the atomic group:
      • \((?<DEPTH>)| - an open ( and an empty string is pushed on the DEPTH group stack or
      • \)(?<-DEPTH>)| - a closing ) and an empty string is popped off the DEPTH group stack or
      • [^()]+ - 1+ chars other than ( and )
    • )* - zero or more repetitions
    • (?(DEPTH)(?!)) - a conditional construct that checks if the number of close and open parentheses is balanced
  • ) - end of R named group
  • \) - a closing )
  • | - or
  • (?<R>&&|\|\|) - another occurrence of Group R matching either of the 2 subpatterns:
    • && - a && substring
    • | - or
    • \|\| - a || substring.

enter image description here

C# code:

var pattern = @"\((?<R>(?>\((?<DEPTH>)|\)(?<-DEPTH>)|[^()]+)*(?(DEPTH)(?!)))\)|(?<R>&&|\|\|)";
var results = Regex.Match(input, pattern)
    .Cast<Match>()
    .Select(m => m.Groups[1].Value)
    .ToList();

Upvotes: 4

ctwheels
ctwheels

Reputation: 22817

Brief

You can use the regex below, but I'd still strongly suggest you write a proper parser for this instead of using regex.


Code

See regex in use here

\(((?>\((?<DEPTH>)|\)(?<-DEPTH>)|.?)*(?(DEPTH)(?!)))\)|&{2}|‌​\|{2}

Usage

See regex in use here

using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main()
    {
        string input = "((isoCode=s)||(isoCode=a))&&(title=s)&&((ti=2)&&(t=2))||(t=2&&e>5)";
        string pattern = @"\(((?>\((?<DEPTH>)|\)(?<-DEPTH>)|.?)*(?(DEPTH)(?!)))\)|&{2}|\|{2}";
        MatchCollection matches = Regex.Matches(input, pattern);
        foreach (Match match in matches)
        {
            Console.WriteLine(match.Groups[1].Success ? match.Groups[1].Value : match.Groups[0].Value);
        }
    }
}

Result

(isoCode=s)||(isoCode=a)
&&
title=s
&&
(ti=2)&&(t=2)
||
t=2&&e>5

Upvotes: 1

Related Questions