How to? But i need a parser, that parse a string only once and has an interface like this
Func<double,double> MathEvaluator(string input)
or like this
LambdaExpression MathEvaluator(string input)
does it exists?
How to? But i need a parser, that parse a string only once and has an interface like this
Func<double,double> MathEvaluator(string input)
or like this
LambdaExpression MathEvaluator(string input)
does it exists?
I'd like to refer to this thread, quoting the results, that were provided by the answers of Rick, Oliver and Max.
You need to ponder, which fits your requirements best. E.g. Math Parser .NET supports ^
for powers and the others don't.
so i maked a lib, if u want, you can use it, it's fine enough i think. There's some regex, that replace structures like a^b to Math.Pow(a,b) etc. It might be better, but it's hard work for me, but i'm working on it.
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.CSharp;
namespace MathEvalNS
{
public class MathEvaluator
{
private readonly Delegate parsedFunction;
private readonly string normalized;
public double Invoke(double x)
{
if (parsedFunction == null)
throw new NullReferenceException("No function to invoke");
return (double)parsedFunction.DynamicInvoke(x);
}
private const string Begin =
@"using System;
namespace MyNamespace
{
public static class LambdaCreator
{
public static Func<double,double> Create()
{
return (x)=>";
private const string End = @";
}
}
}";
public MathEvaluator(string input)
{
normalized = Normalize(input);
var provider = new CSharpCodeProvider();
var parameters = new CompilerParameters { GenerateInMemory = true };
parameters.ReferencedAssemblies.Add("System.dll");
CompilerResults results = provider.CompileAssemblyFromSource(parameters, Begin + normalized + End);
try
{
var cls = results.CompiledAssembly.GetType("MyNamespace.LambdaCreator");
var method = cls.GetMethod("Create", BindingFlags.Static | BindingFlags.Public);
parsedFunction = (method.Invoke(null, null) as Delegate);
}
catch (FileNotFoundException)
{
throw new ArgumentException();
}
}
private string Normalize(string input)
{
return input.ReplaceMath().ReplacePow().ReplaceMultipling().ReplaceToDoubles();
}
}
public static class StringHelper
{
public static string ReplaceMultipling(this string input)
{
return Regex.Replace(input, @"(\d+)(x)", @"$1*$2");
}
public static string ReplacePow(this string input)
{
var result = input.ReplacePow(@"(\d*x)\^(\d+\.?\d*)");
return result.ReplacePow(@"\(([^\^]+)\)\^(\d+\.?\d*)");
}
private static string ReplacePow(this string input, string toReplace)
{
return Regex.Replace(input, toReplace, "Math.Pow($1,$2)");
}
public static string ReplaceToDoubles(this string input)
{
return Regex.Replace(input, @"(\d+)(?:[^\.]\d+)", "$1.0");
}
public static string ReplaceMath(this string input)
{
return
input.ReplaceMath("sin", @"Math.Sin")
.ReplaceMath("cos", @"Math.Cos")
.ReplaceMath("ctg", @"1.0/Math.Tan")
.ReplaceMath("tg", @"Math.Tan");
}
private static string ReplaceMath(this string input, string name, string dotNetName)
{
return Regex.Replace(input, name, dotNetName, RegexOptions.IgnoreCase);
}
}
}
I have a MathParser: http://github.com/MathewSachin/MathParser
I Expect that what you want can be done like this:
Fuc<double, double> Parse(string Expression)
{
MathParser P = new MathParser();
Variable V = new Variable("x", 0); // The Variable you use with default value
P.Variables.Add(V);
P.Parse(Expression);
return (Input) =>
{
V.Value = Input;
return P.Evaluate();
}
}
The Only thing i'm afraid is of Garbage Collection.