Hallo.
Ich würde gerne eine Bedingung in einen String packen und diesen dann auf boolsche Richtigkeit prüfen:
bool istrue=ChkIfTrue("123>4"); // true
istrue=ChkIfTrue("123==4"); // false
istrue=ChkIfTrue("23+8!=22+9"); // false
Ist so etwas überhaupt mit vertretbaren Aufwand möglich? Wie gehe da richtig ran?
Mein Haus, mein Viertel, mein Blog
Hallo HeinzTomato,
sieh dir mal diesen Thread an: Boolsche Funktion zerlegen und auswerten.
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
Du müsstest den String parsen. Hilfreich ist vielleicht ein Blick auf das Interpreter-Pattern.
LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
Hat alles leider nur halb geholfen. Ich habe nun einen mathematischen parser (zu meiner Schande muss ich gestehen: Von Sourceforge) im einfache boolsche Operationen erweitert:
Parser prs = new Parser();
prs.parseBool("23+10==33&&12-5!=7"); // False:
private bool? parseBoolDetail(string expression, string splitter)
{
double? left=null;
double? right=null;
if (expression.Contains(splitter))
{
string leftSide = expression.Substring(0, expression.IndexOf(splitter));
string rightSide = expression.Substring(expression.IndexOf(splitter) + splitter.Length);
if (this.Evaluate(leftSide))
{
left = Value;
}
if (this.Evaluate(rightSide))
{
right = Value;
}
if (left.HasValue && right.HasValue)
{
switch (splitter)
{
case "!=":
case "<>":
return left != right;
case "==":
return left == right;
case "<=":
return left <= right;
case ">=":
return left >= right;
case "<":
return left < right;
case ">":
return left>right;
default:
return null;
}
}
}
return null;
}
public bool? parseBool(string parseString)
{
// && und || geht, KLAMMERN aber nicht!
bool? retVal = null;
// ODER-Verknüpfung:
string[] orParses = parseString.Split(new string[] { "||" }, StringSplitOptions.None);
if (orParses.Length > 1)
{
retVal = false;
for (int i = 0; i < orParses.Length; i++)
{
retVal |= parseBool(orParses[i]);
}
}
else
{
// UND-Verknüpfung
string[] andParses = parseString.Split(new string[] { "&&" }, StringSplitOptions.None);
if (andParses.Length > 1)
{
retVal = true;
for (int i = 0; i < andParses.Length; i++)
{
retVal &= parseBool(andParses[i]);
}
}
else
{
retVal=null;
retVal = retVal ?? parseBoolDetail(parseString, "!=");
retVal = retVal ?? parseBoolDetail(parseString, "==");
retVal = retVal ?? parseBoolDetail(parseString, "<>");
retVal = retVal ?? parseBoolDetail(parseString, ">=");
retVal = retVal ?? parseBoolDetail(parseString, "<=");
retVal = retVal ?? parseBoolDetail(parseString, "<");
retVal = retVal ?? parseBoolDetail(parseString, ">");
}
}
return retVal;
}
Wie man erkennen kann, relativ "händisch". Das erkennen von Klammern im boolschen Bereich habe ich nicht durchgeführt, da die Bedingungen eher simpel gestrickt sein sollen und notfalls einfach so umgestellt werden soll, dass die Klammer unnötig werden.
Mein Haus, mein Viertel, mein Blog
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
vieleicht code erzeugen, den ausführen, und dann das ergebnis abfangen
Gruß pdelvo
Hallo pdelvo,
vieleicht code erzeugen, den ausführen, und dann das ergebnis abfangen
Zeig vielleicht mal ein Beispiel.
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
Mal schnell mit einem Internetcode zusammengeschuhstert. Es funktioniert aber und erzeugt richtige ergebnisse:
using System;
using System.Reflection;
using System.CodeDom.Compiler;
using System.Text;
namespace TrueFalse
{
class Program
{
static void Main(string[] args)
{
Console.Write("Enter text -> ");
string textInput = Console.ReadLine();
Assembly assembly = CompileCode(textInput);
object o = assembly.CreateInstance("gfoidl.Code.Test");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("Ergebnis");
object result = mi.Invoke(o, new object[]{});
Console.WriteLine(result);
Console.ReadKey();
}
public static Assembly CompileCode(string inputCode)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder();
sb.AppendLine(@"using System;");
sb.AppendLine(@"namespace gfoidl.Code{");
sb.AppendLine(@"public class Test{");
sb.AppendLine(@"public bool Ergebnis(){");
sb.AppendLine("return " + inputCode + " ;");
sb.AppendLine(@"}}}");
CompilerResults cr =
provider.CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0)
{
Console.WriteLine(cr.Errors[0].ErrorText);
return null;
}
return cr.CompiledAssembly;
}
}
}
Gruß pdelvo
Hallo pdelvo,
okay, per Reflection funktioniert das sicher, aber ich halte es weder für einen eleganten noch für einen performanten Ansatz.
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
Ich finde diese Lösung besser, als tausende Libs von Sourceforge und co runterzuladen, von welchen man nur einen Bruchteil der Funktionalitäten braucht. Es müssen beim Programstart diese Assemlies geladen. Das braucht auch Systemrecourcen. Außerdem wird die größe des Programms mit den ganzen dlls viel größer.
Gruß pdelvo
Schaut mal im IRC vorbei:
Server: irc.euirc.net
Channel: #C#
Siehe auch:
String in Bedingung umwandeln - elegante Lösung gesucht
Formelparser (kostenlose Komponente)
Parser für mathematische Formeln (kostenlose Komponente)