用值替换变量名
本文关键字:变量名 替换 | 更新日期: 2023-09-27 18:28:13
我定义了一个具有以下值的字符串:
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;
这个库似乎可以满足您的需要http://csharpeval.codeplex.com/wikipage?title=Usage&referringTitle=主页
完成拆分后,按顺序遍历字典中的每个值,并将这些值(foo)作为临时动态对象的成员(如果您使用的是.net4,如果不是字典)。
然后使用库计算第二个表达式,将结果存储在临时对象/字典中,然后继续。
您还需要一个变量及其值的数组或字典(例如Foo,5)。将分号(filterMe.Split(";")上的字符串拆分为一个数组以获取元素,然后循环并拆分"="上的元素,使用返回数组的array[0]作为字典中的键,array[1]作为值。最后循环遍历变量和值的数组,用它们的正确值替换键。为了执行计算(例如foo-5),我会创建一个Func<string, string, int>
,它从字典中接受要执行计算的2个int作为字符串,删除运算符,将它们解析为int,然后使用运算符的字符串来决定执行哪个运算(+、-等),最后返回计算值的int(或我猜是字符串)
以下测试通过:(完全没有考虑性能)
[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"]);
}
这将起作用:
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])*