很抱歉,如果我的标题偏离了,但我不知道从哪里开始。
我提出了一个小格式,允许我在json文件中写一些小步骤。人们都知道天蓝色的资源模板,它的灵感来自于此。
{
"steps": [
{
"command": "mpc-info -i [laz input directory] -c [number processes]",
"outputs": {
"AABB": "[split(regex(stdout,\"\\('AABB: ', (.*?)\\)\",$1))]"
}
}
]
}
如果我想为那些" []"编写我自己的解析器,我该从哪里开始文件中的字符串?
目标是我可以轻松添加可用于编写表达式的新函数/变量。我想在dotnet core netstandard 2.0上运行的c#代码中定义所有这些。
因此,在上面的特定实例中,宿主程序将运行该命令并在stdout上生成一些输出。我现在需要我的代码来解析输出字符串
[split(regex(stdout,\"\\('AABB: ', (.*?)\\)\",$1))]
并将其转换为将在变量stdout上运行Regex匹配的代码,并将第一个捕获组作为参数返回到split函数,该函数将创建项的数组对象并在结尾处替换字符串JToken对象。
有关读取内容的任何指示或可以启动它的示例代码。
我的naiv approch只会编写一些代码,可以进行一些搜索和替换并解决这个小例子,但是如果我想用更多的函数来改进我的小框架等等。
我从哪里开始?
答案 0 :(得分:1)
在Twitter朋友的帮助下,我设法用Sprache解决了这个问题。
stdout.txt
Completed 100.00%!()
('AABB: ', 480000, 6150000, -1580, 530000, 6200000, 755)
('#Points:', 20517377941)
('Average density [pts / m2]:', 8.2069511764)
('Suggested number of tiles: ', 16.0)
('Suggested Potree-OctTree CAABB: ', 480000, 6150000, -1580, 530000, 6200000, 48420)
('Suggested Potree-OctTree spacing: ', 205.0)
('Suggested Potree-OctTree number of levels: ', 11)
Suggested potreeconverter command:
$(which PotreeConverter) -o <potree output directory> -l 11 -s 205 --CAABB "480000 6150000 -1580 530000 6200000 48420" --output-format LAZ -i <laz input directory>
Finished in 7.63 seconds
以及显示其工作原理的单元测试
[TestMethod]
public void TestMethod1()
{
var parser = new ExpressionParser();
parser.Functions["add"] = (arguments) =>
arguments.Aggregate(0.0, (acc, argument) => acc + argument.ToObject<double>());
parser.Functions["split"] = (arguments) => JArray.FromObject(arguments.Single().ToString().Split(","));
parser.Functions["regex"] = RegexFunc;
Assert.AreEqual(4.0, parser.Evaluate("[add(2,2)]"));
Assert.AreEqual(7.0, parser.Evaluate("[add(2,2,3)]"));
Assert.AreEqual(3.0, parser.Evaluate("[add(2,2,-1)]"));
Assert.AreEqual(4.0, parser.Evaluate("[add(2,2,0,0)]"));
var stdout = File.ReadAllText("stdout.txt");
var test = parser.Evaluate("[split(regex(\"testfoo\",\"test(.*)\",\"$1\"))]");
Assert.AreEqual("[\"foo\"]",test.ToString( Newtonsoft.Json.Formatting.None));
parser.Functions["stdout"] = (arguments) => stdout;
parser.Functions["numbers"] = (arguments) => new JArray(arguments.SelectMany(c => c).Select(c => double.Parse(c.ToString())));
var AABB = parser.Evaluate("[numbers(split(regex(stdout(2),\"\\('AABB: ', (.*?)\\)\",\"$1\")))]");
CollectionAssert.AreEqual(new[] { 480000, 6150000, -1580, 530000, 6200000, 755 }, AABB.ToObject<int[]>());
}
和实际实施
public class ConstantEvaluator : IJTokenEvaluator
{
private string k;
public ConstantEvaluator(string k)
{
this.k = k;
}
public JToken Evaluate()
{
return JToken.Parse(k);
}
}
public class DecimalConstantEvaluator : IJTokenEvaluator
{
private decimal @decimal;
public DecimalConstantEvaluator(decimal @decimal)
{
this.@decimal = @decimal;
}
public JToken Evaluate()
{
return JToken.FromObject(@decimal);
}
}
public class StringConstantEvaluator : IJTokenEvaluator
{
private string text;
public StringConstantEvaluator(string text)
{
this.text = text;
}
public JToken Evaluate()
{
return text;
}
}
public interface IJTokenEvaluator
{
JToken Evaluate();
}
public class FunctionEvaluator : IJTokenEvaluator
{
private string name;
private IJTokenEvaluator[] parameters;
private ExpressionParser evaluator;
public FunctionEvaluator(ExpressionParser evaluator, string name, IJTokenEvaluator[] parameters)
{
this.name = name;
this.parameters = parameters;
this.evaluator = evaluator;
}
public JToken Evaluate()
{
return evaluator.Evaluate(name, parameters.Select(p => p.Evaluate()).ToArray());
}
}
public class ExpressionParser
{
public readonly Parser<IJTokenEvaluator> Function;
public readonly Parser<IJTokenEvaluator> Constant;
private static readonly Parser<char> DoubleQuote = Parse.Char('"');
private static readonly Parser<char> Backslash = Parse.Char('\\');
private static readonly Parser<char> QdText =
Parse.AnyChar.Except(DoubleQuote);
private static readonly Parser<char> QuotedPair =
from _ in Backslash
from c in Parse.AnyChar
select c;
private static readonly Parser<StringConstantEvaluator> QuotedString =
from open in DoubleQuote
from text in QdText.Many().Text()
from close in DoubleQuote
select new StringConstantEvaluator(text);
public Dictionary<string, Func<JToken[], JToken>> Functions { get; set; } = new Dictionary<string, Func<JToken[], JToken>>();
private readonly Parser<IJTokenEvaluator> Number = from op in Parse.Optional(Parse.Char('-').Token())
from num in Parse.Decimal
from trailingSpaces in Parse.Char(' ').Many()
select new DecimalConstantEvaluator(decimal.Parse(num) * (op.IsDefined ? -1 : 1));
public ExpressionParser()
{
Function = from name in Parse.Letter.AtLeastOnce().Text()
from lparen in Parse.Char('(')
from expr in Parse.Ref(() => Function.Or(Number).Or(QuotedString).Or(Constant)).DelimitedBy(Parse.Char(',').Token())
from rparen in Parse.Char(')')
select CallFunction(name, expr.ToArray());
Constant = Parse.LetterOrDigit.AtLeastOnce().Text().Select(k => new ConstantEvaluator(k));
}
public JToken Evaluate(string name, params JToken[] arguments)
{
return Functions[name](arguments);
}
IJTokenEvaluator CallFunction(string name, IJTokenEvaluator[] parameters)
{
return new FunctionEvaluator(this, name, parameters);
}
public JToken Evaluate(string str)
{
var stringParser = //Apparently the name 'string' was taken...
from first in Parse.Char('[')
from text in this.Function
from last in Parse.Char(']')
select text;
var func = stringParser.Parse(str);
return func.Evaluate();
}
}