在推特朋友的帮助下,我用Sprache解决了这个问题。
标准输出。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();
}
}