2

I am creating a program where I offer a few functions that can be entered by the user. Let's say I have a function to convert a string to upper-case with the function $upper(string) and a function $lower(string). The user can enter those in a text box while using placeholders to insert content (e.g. %T for the title of a song). Using both placeholders and functions, the user can enter a complete naming pattern.

Functions can be nested and I want to execute the inner-most function first. Now I am looking for a Regex to identify it. In english, I am looking for a function (and its value) that does not contain another function.

During my tests, I use hyphens instead of brackets and no $-sign. This is a lot easier to read. So the functions during testing are lower-sometext-.

This is my guess so far:

(lower|upper)-(?!((lower|upper)-.*-))-

I read it as follows:

  • find the word upper or lower,
  • followed by a hyphen,
  • followed by anything that is NOT the word upper or lower, a hyphen, a random number of random characters and a hyphen
  • followed by a hypen.

But that won't even accept lower-sometext-. I am trying different things for more than 2 hours but I can't figure it out...

Peter
  • 239
  • 2
  • 11
  • [Got speed ?](http://regex101.com/r/gL5vF0) – HamZa May 19 '13 at 16:32
  • I need to explicitly look for an existing function in the second part. This example will be illegal with your regex, but is allowed: `$lower(artist (feat other artist))` – Peter May 19 '13 at 16:39
  • What regex flavor are you using, PCRE PHP ? – HamZa May 19 '13 at 20:08
  • [This](http://regex101.com/r/dB7dS8) is the only thing I could came up with inspired from [this awesome answer](http://stackoverflow.com/a/16420841). – HamZa May 20 '13 at 01:18

1 Answers1

1

Use a different approach: Instead of looking for the inner-most function first, start with the outermost function - and resolve its value recursively.

So for the string upper(lower(sometext)) you first "handle" the upper. But before you actually apply ToUpper() you call the same function on its value - in this case lower(sometext). Then you do the same thing again: apply ToLower() to the result of your execute function for the value - in this case only sometext. Since it does not contain a function, the execute method will return sometext and end the recursion.

I have created a function in C#

public string execute(string text)
{
    string pattern = @"(lower|upper)\((.*)\)";
    Match m = Regex.Match(text, pattern);
    if (m.Success)
    {
        switch (m.Groups[1].Value)
        {
            case "lower":
                return execute(m.Groups[2].Value).ToLower();
            case "upper":
                return execute(m.Groups[2].Value).ToUpper();
            default:
                return null;
        }
    }
    else
        return text;
}

And you can just call the function with your string:

string result = "upper(lower(sometext))";

Again: The important part is inside the switch: BEFORE you call ToLower() or ToUpper() you call the execute method for the value. The result of this function will ALWAYS be a literal and never contain a function. Also, it scales really well.

Jan
  • 2,099
  • 2
  • 17
  • 28