用于嵌套函数的 C# RegEx

标签 c# regex

我无法在 C# 中使用 RegEx 评估以下表达式。

add(1, 2, sub(4, add(1, 2)), div(4, 2))

这将被评估如下。
=> add(1, 2, sub(4, 3), 2)
=> add(1, 2, 1, 2)
=> 6

函数是从正则表达式中提取的,参数是任意数字。提前致谢。

这是我正在尝试的:
class Program
{
    static Regex extractFuncRegex = new Regex(@"(?<func>add|sub|div)\s*\((?<params>.*)\)$", RegexOptions.ExplicitCapture);
    static Regex extractArgsRegex = new Regex(@"([^,]+\(.+?\))|([^,]+)");


    static void Main(string[] args)
    {
        string test = @"add(1, 2, sub(4, add(1, 2)), div(4, 2))";
        Console.WriteLine(ParseFunction(test));
        Console.ReadLine();
    }

    static string ParseFunction(string expr)
    {
        expr = extractFuncRegex.Replace(expr, (m) =>
            {
                string func = m.Groups["func"].Value;
                string param = m.Groups["params"].Value;

                Console.WriteLine("Function: {0}", func);

                MatchCollection paramCollection = extractArgsRegex.Matches(param);
                List<string> pa = new List<string>();

                foreach (Match item in paramCollection)
                {
                    string p = item.Groups[0].Value.Trim();
                    Console.WriteLine("\tParameter: {0}", p);

                    if (extractFuncRegex.IsMatch(p))
                        p = ParseFunction(p);

                    pa.Add(p);
                }

                switch (func)
                {
                    case "add":
                        float a1 = 0;
                        foreach (string item in pa)
                            a1 += float.Parse(item);
                        return a1.ToString();

                    case "sub":
                        return (float.Parse(pa[0]) - float.Parse(pa[1])).ToString();

                    case "div":
                        return (float.Parse(pa[0]) / float.Parse(pa[1])).ToString();

                    default:
                        return expr;
                }
            });

        return expr;
    }
}

如果你调试,你可以看到,有问题要解析
sub(4, add(1, 2))

最佳答案

到目前为止,您显然在这方面做得很好,所以我不会说“不要使用正则表达式,扔掉它并使用其他东西” - 我将展示如何使您的代码与最小的变化。

首先,更改您的 extractFuncRegex

@"(?<func>add|sub|div)\s*\((?<params>[^()]*)\)"

我已更换 .*params[^()]* 组.这意味着它只会匹配一个不包含任何其他函数调用的函数调用——因为这是我们唯一可以直接处理的事情。我还删除了尾随 $让它工作。

现在的诀窍是调用ParseFunctionextractFuncRegex.Replace直到没有更换。例如,您可以调用 extractFuncRegex.Replace在这样的循环中(未经测试):
bool doneWork = true;
while (doneWork)
{
    doneWork = false;
    expr = extractFuncRegex.Replace(expr, (m) =>
        {
            doneWork = true;
            ...
        });
}
...

使用它,您可以获得一系列逐渐简化的表达式。在每个阶段,只有最深的函数调用被替换。
add(1, 2, sub(4, add(1, 2)), div(4, 2))
                 |--------   |--------
add(1, 2, sub(4, 3        ), 2        )
          |----------------
add(1, 2, 1                , 2        )
|--------------------------------------
6

关于用于嵌套函数的 C# RegEx,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27920020/

相关文章:

regex - QTP:如何在检查点属性编辑对话框中获取 "complex value"编辑控件?

c# - 在自动启动服务中连接到 SQL Server 失败,在手动启动时有效。 SQL Server 未就绪,但服务已启动

c# - 将制表符转换为 RichTextBox 中的空格

c# - 将普通方法转换为静态方法有什么好处?

javascript - 正则表达式单词边界空间

java - 检查几个正则表达式的字符串并说出哪个匹配

c# - 如何内存分析在 Visual Studio 中运行的单元测试

c# - 非泛型类中的泛型方法

PHP Word Censor 帮助,使用正则表达式根据标准审查单词

regex - 如何使用 Windows 命令行工具或批处理文件从日志文件中提取行?