2

我定义了一个具有以下值的字符串:

var filterMe = "foo=1;bar=foo+5;foobar=foo+5-bar;";

并创建一个拆分字符串的数组,如下所示:

var splitter = filterMe.Split(';');

Dictionary<string,string> dictionary = new Dictionary<string, string>();

foreach (var split in splitter)
        {
            if (!string.IsNullOrEmpty(split))
            {
                var part = split.Split('=');
                dictionary.Add(part[0], part[1]);
            }
        }

所以字典中这个“bar = foo + 5”的结果被定义为这个“bar”,“foo + 5”。

现在我的问题是,如何将值 "foo+5" 中的 "foo" 更改为包含值 "1" 的键 "foo" ?字符串 filterMe 将更长且动态,因此它将包含多个变量 (foo)。

编辑:由于我的问题似乎有点令人困惑,请参阅下面的如何替换它:

var foo=200;
var bar = foo+300;

然后变量 bar 应变为:

var bar = 200+300;
4

4 回答 4

0

这个库似乎可以满足您的需求 http://csharpeval.codeplex.com/wikipage?title=Usage&referringTitle=Home

进行拆分后,按顺序检查字典中的每个值,并将值 (foo) 作为临时动态对象的成员(如果您使用的是 .net 4,如果不是字典)。

然后使用库来评估第二个表达式,将其结果存储在临时对象/字典中,然后继续。

于 2013-08-19T07:54:30.043 回答
0

以下测试通过:(完全没有考虑性能)

[Test]
public void tst()
{
    var filterMe = "foo=1;bar=foo+5;foobar=foo+5-bar;";
    var dic = filterMe.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
                      .ToDictionary(x => x.Split('=')[0], x => x.Split('=')[1]);

    while (true)
    {
        var kvpToApply = dic.Keys
                            .Join(dic, x => true, y => true, (key, value) => new { key, value })
                            .FirstOrDefault(x => x.value.Value.Contains(x.key));
        if (kvpToApply != null)
        {
            dic[kvpToApply.value.Key] = kvpToApply.value.Value.Replace(kvpToApply.key, dic[kvpToApply.key]);
        }
        else
        {
            break;
        }
    }

    Assert.AreEqual("1", dic["foo"]);
    Assert.AreEqual("1+5", dic["bar"]);
    Assert.AreEqual("1+5-1+5", dic["foobar"]);
}
于 2013-08-19T08:16:23.737 回答
0

You would need an array or Dictionary of your variables and their values (eg Foo, 5) as well. Split the string on the semi-colons (filterMe.Split(";") into an array to get the elements, then loop through and split the elements on the "=", using array[0] of the returned array as the key in the dictionary and array[1] as the value. Finally loop through the array of variables and values to replace the keys with their correct value. To perform the calculation (eg foo-5) I would create a Func<string, string, int> that accepts the 2 ints you want to perform the calculation on as strings from the dictionary, removes the operator, parses them as ints then uses the string of the operator to decide which operation (+, -, etc...) to perform, finally returning an int (or string I guess) of the calculated value

于 2013-08-19T08:01:06.543 回答
0

这将起作用:

public enum ParserState
{
    ExpectSign = 0,
    ExpectValue = 1
}

public static void Parse()
{
    string filterMe = "foo=1;bar=foo+5;foobar=foo+5-bar;";

    var rows = filterMe.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

    Dictionary<string, int> locals = new Dictionary<string, int>();

    foreach (string split in rows)
    {
        var row = split.Split('=');

        if (row.Length != 2)
        {
            throw new Exception();
        }

        string name = row[0].Trim();
        string exp = row[1].Trim();

        if (!Regex.IsMatch(name, "^[A-Za-z_]+$"))
        {
            throw new Exception();
        }

        Regex rx = new Regex(@"\G(?:(?<local>[A-Za-z_]+)|(?<constant>[0-9]+)|(?<sign>[+-]))");

        var subExps = rx.Matches(exp).OfType<Match>().ToArray();

        if (subExps.Length == 0 || subExps[subExps.Length - 1].Index + subExps[subExps.Length - 1].Length != exp.Length)
        {
            throw new Exception();
        }

        int result = 0;

        ParserState state = ParserState.ExpectValue;
        string currentSign = "+";

        foreach (var subExp in subExps)
        {
            {
                Group sign = subExp.Groups["sign"];

                if (sign.Success)
                {
                    if (state != ParserState.ExpectSign)
                    {
                        throw new Exception();
                    }

                    currentSign = sign.ToString();

                    state = ParserState.ExpectValue;

                    continue;
                }
            }

            {
                Group local = subExp.Groups["local"];

                if (local.Success)
                {
                    if (state != ParserState.ExpectValue)
                    {
                        throw new Exception();
                    }

                    int value;

                    if (!locals.TryGetValue(local.ToString(), out value))
                    {
                        throw new Exception();
                    }

                    result = Operation(result, value, currentSign);

                    state = ParserState.ExpectSign;
                }
            }

            {
                Group constant = subExp.Groups["constant"];

                if (constant.Success)
                {
                    if (state != ParserState.ExpectValue)
                    {
                        throw new Exception();
                    }

                    int value = int.Parse(constant.ToString());

                    result = Operation(result, value, currentSign);

                    state = ParserState.ExpectSign;
                }
            }

            if (state != ParserState.ExpectSign)
            {
                throw new Exception();
            }
        }

        locals[name] = result;
    }
}

private static int Operation(int result, int value, string currentSign)
{
    if (currentSign == "+")
    {
        return result + value;
    }

    if (currentSign == "-")
    {
        return result - value;
    }

    throw new ArgumentException();
}

但是请注意,如果您想在运算符 (so that ) 或数字符号 (so ) 或 ( )()之间引入或不同的优先级,这将变得非常困难。1 * 2 + 3 == (1 * 2) + 31 + -2-2 + 1

有一些工具/库可以做这类事情。

最后,它考虑以这种格式制作的“行”:

local = [local|constant]([+|-][local|constant])*
于 2013-08-19T08:17:20.147 回答