-1

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?

Psilon
  • 35
  • 4
  • possible duplicate of [I need a fast runtime expression parser](http://stackoverflow.com/questions/4392022/i-need-a-fast-runtime-expression-parser) – David Heffernan Feb 28 '13 at 19:34

3 Answers3

2

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.

Community
  • 1
  • 1
Michael Schnerring
  • 3,584
  • 4
  • 23
  • 53
  • Yet another math parser is [YAMP](https://github.com/FlorianRappl/YAMP) (pardon the pun). Extensive list of mathematical functions, written entirely in C# and even available as a portable class library for Windows Store, Windows Phone and Silverlight applications. – Anders Gustafsson Feb 28 '13 at 19:52
  • I don't need parse it every time it calls, i need get a Delegate with function. For example, input 2*x*cos(x)+3*x*x*sin(x) it's not algebraic parser, it's math evaluator, that return a function, that i can call with any parameters. Now i solved it like i post below. Iron python = it's good, cuz of using eval(...), but i don't like multilanguage project. – Psilon Mar 01 '13 at 05:49
1

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);
    }
}
}
Psilon
  • 35
  • 4
0

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.

Mathew Sachin
  • 1,429
  • 1
  • 15
  • 20