我使用以下值定义一个字符串:
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;
变量栏应该变为:
var bar = 200+300;
答案 0 :(得分:0)
这个库似乎可以满足您的需求 http://csharpeval.codeplex.com/wikipage?title=Usage&referringTitle=Home
执行拆分后,按顺序遍历字典中的每个值,并将值(foo)作为临时动态对象的成员(如果您使用.net 4,如果不是字典)
然后使用库来评估第二个表达式,将其结果存储在临时对象/字典中,然后继续。
答案 1 :(得分:0)
您还需要变量的数组或字典及其值(例如Foo,5)。将分号(filterMe.Split(“;”)上的字符串拆分为数组以获取元素,然后循环并拆分“=”上的元素,使用返回数组的数组[0]作为键在字典和数组[1]中作为值。
最后循环遍历变量和值数组,以用正确的值替换键。为了执行计算(例如foo-5),我将创建一个Func<string, string, int>
,它接受你要在字典中作为字符串执行计算的2个int,删除运算符,将它们解析为int,然后使用字符串运算符决定执行哪个操作(+, - 等...),最后返回计算值的int(或我猜的字符串)
答案 2 :(得分: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"]);
}
答案 3 :(得分: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();
}
但请注意,如果您想在运算符之间引入()
或不同的优先级(以便1 * 2 + 3 == (1 * 2) + 3
)或数字符号(1 + -2
)或(-2 + 1
)变得非常困难。
有一些工具/库可以完成这类工作。
最后,它会考虑以这种格式制作的“行”:
local = [local|constant]([+|-][local|constant])*