1

I'm trying to parse function name and its parameters to update the string contents. I'm storing function call in a string and before invoking it i need to modify it and then invoke. Following is string containing function.

var expression = "AreEqual  ( \"test\" ,  Obj.Prop ) && AreEqual ( 1 , 2 ) && AREeQuAl( Obj.Prop , 1 )&& AreEqual (\"\\\"\\\",\" , 2 ) AND AreEqual (',' , ',' ) AreEqual ( \"A,B\" , Obj.Prop ) ";

var expectedOutPut = "MyClass.AreEqual( new (\"test\" AS A) , new ( Obj.Prop AS A) ) && MyClass.AreEqual ( new( 1 AS A ), new ( 2 AS A) ) && MyClass.AREeQuAl( new (Obj.Prop AS A) , new ( 1 AS A) ) && MyClass.AreEqual (new ( \"\\\"\\\",\" AS A) , new ( 2 AS A)  ) && MyClass.AreEqual (new (',' AS A) , new( ',' AS A )) && MyClass.AreEqual ( new (\"A,B\" AS A) ,new ( Obj.Prop AS A) )";

I tried following regex but it's breaking in valid commas inside double quotes.

@"(AreEqual.*?\()\s*([^,]+?)\s*(?=,|$)"

using System;
using System.Text.RegularExpressions;

public class Program
{
    public static void Main()
    {
        string pattern = @"(AreEqual.*?\()\s*([^,]+?)\s*(?=,|$)";
        string input = @"AreEqual  ( ""test"" ,  Obj.Prop ) && AreEqual ( 1 , 2 ) && AREeQuAl( Obj.Prop , 1 )&& AreEqual (""\""\"","" , 2 ) AND AreEqual (',' , ',' ) AreEqual ( ""A,B"" , Obj.Prop )";

        RegexOptions options = RegexOptions.Multiline | RegexOptions.IgnoreCase;

        foreach (Match m in Regex.Matches(input, pattern, options))
        {
            Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
        }
        Console.ReadLine();
    }
}
13
  • I still struggling with the expected outcome. Could you provide it? Commented Apr 12, 2019 at 5:19
  • 1
    Hi @MongZhu I've updated the question. Basically i'm updating every function call with MyClass.AreEqual(new ( parameter1Here AS A) , new ( parameter2Here AS A) ). Commented Apr 12, 2019 at 5:39
  • its a mistake you have AREeQual and AreEqual in expected output? and in input? i suppose the name is the same... Commented Apr 12, 2019 at 6:33
  • @mjwills Actually these are expressions executed by Dynamic Linq Library. AreEqual is a function taking 2 input as objects and then compares any heterogeneous type (I.e. string and int or int decimal) for equality. Dynamic Linq Library cannot internally cast decimal to object. So i'm creating this layer which will convert user expressions input parameters to object. E.G AreEqual ( 1 , 1.0) to MyClass.AreEqual( new ( 1 as A ) , new ( 1.0 as A ) ) Commented Apr 12, 2019 at 6:42
  • 1
    Let's narrow the task: do you want to support interpolated, verbatim, all types of C# string literals? Commented Apr 12, 2019 at 7:15

2 Answers 2

1

I tried to match the items into groups and then format a new string using those groups.

string pattern = @"(AreEqual)\s*\((\s*[\""']*[\w,\\]*(.\w+)*[\""']*\s*),(\s*[\""']*[\w,\\]*(.\w+)*[\""']*)\s*\)";
string input = @"AreEqual  ( ""test"" ,  Obj.Prop ) && AreEqual ( 1 , 2 ) && AREeQuAl( Obj.Prop , 1 )&& AreEqual (""\""\"","" , 2 ) AND AreEqual (',' , ',' ) AreEqual ( ""A,B"" , Obj.Prop )";

RegexOptions options = RegexOptions.Multiline | RegexOptions.IgnoreCase;

List<string> expectedOutputParts = new List<string>();
foreach (Match m in Regex.Matches(input, pattern, options))
{
    string newstring = $"MyClass.{m.Groups["1"]}( new ({m.Groups["2"]} AS A) , new ({m.Groups["4"]} AS A) )";
    expectedOutputParts.Add(newstring);         

}   

Console.WriteLine(string.Join(" && ", expectedOutputParts));

Output:

MyClass.AreEqual( new ( "test" AS A) , new ( Obj.Prop AS A) ) && MyClass.AreEqual( new ( 1 AS A) , new ( 2 AS A) ) && MyClass.AREeQuAl( new ( Obj.Prop AS A) , new ( 1 AS A) ) && MyClass.AreEqual( new (',' AS A) , new ( ',' AS A) ) && MyClass.AreEqual( new ( "A,B" AS A) , new ( Obj.Prop AS A) )

Disclaimer:

this version does not contain the AreEqual (""\""\"","" , 2 ) part. I still haven't figured that out.

Sign up to request clarification or add additional context in comments.

5 Comments

i tried this but it is failing at Empty brackets "". regex101.com/r/iZ5bYH/3
@MaheshJadhav the we have to change [\w,\\]+ to make it optional: [\w,\\]* . empty brackets were not part of your example. I edited my post. Now it works
@MaheshJadhav can you tell me how you match the case that I did not catch?
var regex = @"(AreEqual)\s*((\s*[\"')(+&!$*>=:\/\\<]*[\w,\]*(.\w+)*[\"')(+&!$*>=:\/\\<]*\s*),(\s*[\"')(+&!$*>=:\/\\<]*[\w,\]*(.\w+)*[\"')(+&!$*>=:\/\\<]*)\s*)". this rescued me.
public string GetExp(string expression){ string specialChars = @"\""')(+&!$*>=:\/\\<"; string pattern = @"(AreEqual)\s*((\s*[" + specialChars + @"]*[\w,\]*(.\w+)*[" + specialChars + @"]*\s*),(\s*[" + specialChars + @"]*[\w,\]*(.\w+)*[" + specialChars + @"]*)\s*)"; var options = RegexOptions.Singleline | RegexOptions.IgnoreCase; return Regex.Replace(expression, pattern, m => m.Groups[1].Value + "( new ( " + m.Groups[2] + " as Object ) , new ( " + m.Groups["4"] + " as Object ) )", options);}
0

here is a generic solution:

        var texte = "AreEqual  ( \"test\" ,  Obj.Prop ) && AreEqual ( 1 , 2 ) && AREeQuAl( Obj.Prop , 1 )&& AreEqual (\",\" , 2 ) AND AreEqual (',' , ',' ) AreEqual(\"A,B\", Obj.Prop)";

        //Extract function
        MatchCollection matches = Regex.Matches(texte, @".+?(?=\()");
        var function = Regex.Matches(texte, @".+?(?=\()")[0].ToString().Trim();


        var patternARGS = @"(?<=\().+? (?=\))";
        var patternExtractARGS = @"""[^, ]* , [^, ]*""( , )""[^, ]* , [^,]*""|[^, ]* , [^, ]*""( , )[^""]+""|[^""]+( , )""[^,]* , [^,]*""|( , )";

        // extract all arg between parenthesis
        matches = Regex.Matches(texte, patternARGS);

        //extract all args from previous result, with the difficulty to identify the right ','
        List<String> args = new List<String>();
        foreach (Match m in matches)
        {
            System.Diagnostics.Debug.WriteLine($"{m}");
            MatchCollection x = Regex.Matches(m.ToString(),patternExtractARGS);
            GroupCollection commas = x[0].Groups;

            var index = (commas.SyncRoot as Match).Index;
            var len = (commas.SyncRoot as Match).Length;
            var a1 = m.ToString().Substring(0, index);
            var a2 = m.ToString().Substring(index + len - 1);
            args.Add($"MyClass.{ function}( new ({a1}), new ({a2}))");
        }


        //extract conditions && AND...)
        var patternCONDITION = @"(?<=\)).+?(?=(?i: " + function + "))";
        matches = Regex.Matches(texte, patternCONDITION);



        var output = args[0];
        for(int i = 1;i<args.Count;i++)
        {
            output = output + $" {matches[i - 1].ToString().Trim()} {args[i]}";
        }

result in output.

1 Comment

i tried this but its expecting all expression containing 'AreEqual' function and failing at : var texte = " 2 == 4 && AreEqual ( \"test\" , Obj.Prop ) && AreEqual ( 1 , 2 ) && AREeQuAl( Obj.Prop , 1 )&& AreEqual (\",\" , 2 ) AND AreEqual (',' , ',' ) AreEqual(\"A,B\", Obj.Prop)";

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.