Benutzer mit den meisten Antworten
Dynamische Formeln auf True | False prüfen

Frage
-
Hallo Liebe Forum Leser,
das ist mein erster Thread und ich hoffe Ihr könnt mir bei folgender Problematik helfen bzw. ich drück mich deutlich genug aus:
Die Aufgabe ist es komplexe und dynamische Wenn -->Dann Bedingungen Benutzerspezifisch festzulegen bsp.:
BoolArray
Bool ID 1 = (dynamisch true|False)
Bool ID 2 = (dynamisch true|False)
Bool ID 3 = (dynamisch true|False)
Bool ID 5 = (dynamisch true|False)
Nun soll der Benutzer anhand einer dynamischen Formel selbst festlegen können inwieweit die einzelnen bools im BoolArray in Abhängigkeit stehen daher Bspw. als string "((1 und 2) oder (3 und 4))" (die Zahlen stehen für die jeweilige ID des bool Arrays)
Die Aufgabe ist nun anhand dieser Bedingung bsp. "((1 und 2) oder (3 und 4))" ein true | false zu erhalten, des weiteren soll die Formel auf logische Richtigkeit geprüft werden.
ich wäre euch sehr dankbar wenn Ihr mir bei dieser für mich schweren Aufgabe behilflich sein könntet
habt vielen lieben dank für die Bemühungen und ich freue mich auf eure Anregungen bzw. Example Quellcode :-)
Antworten
-
Hallo und willkommen im Forum,
im Grunde ist dein Vorhaben nichts anderes als ein Formelparser. du könntest hier alle Zeichen durchgehen und je nach gefundenem Zeichen deinen bisherigen Ausdruck auswerten. Ich habe mal ein kurzes Beispiel erstellt, mit dem du einen erweiterbaren Ansatz hast:static void Main(string[] args) { var x1 = Parse("(0u1)o(2u3)", true, false, true, false);//false var x2 = Parse("(0o1)u(2o3)", true, false, true, false);//true var x3 = Parse("(0u1)u(2u3)", true, false, true, false);//false var x4 = Parse("(0o1)o(2o3)", true, false, true, false);//true } public static bool Parse(string exp, params bool[] bools) { int i = 0; return Parse(exp, bools, ref i); } static bool Parse(string exp, bool[] bools, ref int i) { string curretnExp = "";//Aktuelle Berechnung (o=oder, u=und) int firtstIndex = -1;//Der Index des ersten Werts aus dem Array (für eine Operation) bool? brVal1 = null;//Wert des ersten Klammerausdrucks, wenn einer gefunden wurde for (; i < exp.Length; ++i) { switch (exp[i])//Was für ein Zeichen ist an der Stelle i? { //Operatoren case 'o': case 'u': curretnExp = exp[i].ToString(); break; //Indices der Werte case '0': case '1': case '2': case '3': if (firtstIndex == -1) { //1. Operator firtstIndex = int.Parse(exp[i].ToString());//Index merken break; } else { //2. Operator > Verarbeiten bool firstVal = false; if (firtstIndex != -1) firstVal = bools[firtstIndex];//1. Operator war ein Index else firstVal = (bool)brVal1;//1. Operator war eine Klammer bool res = false; ; switch (curretnExp) { case "o": res = firstVal || bools[int.Parse(exp[i].ToString())]; break; case "u": res = firstVal && bools[int.Parse(exp[i].ToString())]; break; default: throw new ArgumentException();//Unbekannter Operator } //Werte zurück setzen; brVal1 = null; firtstIndex = -1; ++i;//Klammer zu überspringen return res;//Wert zurück geben //Ich gehe hier davon aus, das jeder Operaot in Klammern steht, nach dem Schema (WERT1 OPERATOR WERT2) } //Klammern case '(': ++i;//i um 1 erhöhen um die Klammer zu überspringen var x = Parse(exp, bools, ref i); if (brVal1 == null) { brVal1 = x; break; } else { //2. Operator bool firstVal = false; if (firtstIndex != -1) firstVal = bools[firtstIndex];//1. Operator war ein Index else firstVal = (bool)brVal1;//1. Operator war eine Klammer bool res = false; ; switch (curretnExp) { case "o": res = firstVal || x; break; case "u": res = firstVal && x; break; default: throw new ArgumentException();//Unbekannter Operator } //Werte zurück setzen; brVal1 = null; firtstIndex = -1; ++i;//Klammer zu überspringen return res;//Wert zurück geben } case ')': case ' ': break;//Leerzeichen und Klammer zu ignorieren } } throw new ArgumentException(); //! Fehler, weil eigentlich beim 2. Operator zurück gesprungen werden sollte }
Der Code ist noch weit ausbaufähig, aber es ist ein Ansatz. In meinen 4 kurzen Tests hat es soweit funktioniert. Natürlich kannst du den Code noch optimieren und verbessern. Je anchdem was du alles machen möchtest, brauchst du auch noch weitere Operatoren.
Bisher versteht der Parser nur or und and. Des weiteren verlangt der Code, das jeder Operator mit seinen Werten eingeklammert ist, also (1 or 2) Doppelte Klammern ((1)) sind nicht erlaubt und Leerzeichen werden ignoriert. Wie gesagt, meine Tests zeigten keine Fehler, aber der Code ist auch noch nicht sehr Komplex oder ausgereift.Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.- Als Antwort markiert Stefan (sb) Sonntag, 9. März 2014 15:30
Alle Antworten
-
Hi Stefan,
ganz genau hab ich jetzt nich verstanden was du machen möchtes. Da aus deinen Angaben auch kein Zusammen hang für mich ersichtlich ist. Zb. ID1 und 2 true ID3 und 4 fals, was soll da das Ergenis sein Fals oder True und wie soll man da die Logische Richtigkeit Prüfen.
Ich rate da mal ein bissen und denke das dir Flags weiter helfen könnten.
Das erlaubt den Benutzer alle Möglichen Kompinationen der Werte und du kannst festlegen welche Kombinationen gültig sind.
MFG
Björn -
Zusammenhang
Bsp.:
Variable[0] = true;
Variable[1] = true;
Variable[2] = false;
Variable[3] = false;
Formel Benutzer spezifisch bsp.: (Variable[0] && Variable[1]) || (Variable[2] && Variable[3]) (das kann so ein Anwender natürlich nicht schreiben.
meine Idee war es nun das mit ID´s zu definieren daher so z.B. "((1 und 2) oder (3 und 4))" oder so: "((1 und (2 oder 5)) oder (3 und 4))", die Anwendung soll nun die Formel des Benutzers umwandeln und ein true/false zurückgeben, sofern die eingegebene Formel des Benutzers falsch ist daher z.B. Klammerfehler soll der Benutzer entsprechend darüber informiert werden
Hintergrund:
die Bedingungen werden in einer Datenbank hinterlegt, das Ergebnis dieser Bedingungen kann nur true / false sein anhand der ID möchte ich die Formel auflösen.
Flags entsprechen ja einen 0 oder 1 daher true oder false... ich denke die Richtung ist schon richtig jedoch wie löse ich die dynamische Formel auf?
in diesem Beispiel:
"((1 und 2) oder (3 und 4))" --> return = true
"((1 und 4) oder (2 und 4))" --> return = false
"((1 und 4)( oder (2 und 4))" --> return = "Formel fehlerhaft"
Anwendungsbeispiel
Variable[0] = true|false (ist der Umsatz im Jahr 2013 > 100.000€)
Variable[1] = true|false (ist der netto Gewinn im Jahr 2013 < 100.000€)
Variable[2] = true|false (sind mehr als 10 Mitarbeiter beschäftigt)
...
die Fragen sind vom Anwender individuell definierbar.... (Das ist auch schon fertig und funktioniert)
@Björn hab vielen lieben dank für deine Bemühungen
- Bearbeitet Stefan (sb) Sonntag, 9. März 2014 15:01
-
Hallo und willkommen im Forum,
im Grunde ist dein Vorhaben nichts anderes als ein Formelparser. du könntest hier alle Zeichen durchgehen und je nach gefundenem Zeichen deinen bisherigen Ausdruck auswerten. Ich habe mal ein kurzes Beispiel erstellt, mit dem du einen erweiterbaren Ansatz hast:static void Main(string[] args) { var x1 = Parse("(0u1)o(2u3)", true, false, true, false);//false var x2 = Parse("(0o1)u(2o3)", true, false, true, false);//true var x3 = Parse("(0u1)u(2u3)", true, false, true, false);//false var x4 = Parse("(0o1)o(2o3)", true, false, true, false);//true } public static bool Parse(string exp, params bool[] bools) { int i = 0; return Parse(exp, bools, ref i); } static bool Parse(string exp, bool[] bools, ref int i) { string curretnExp = "";//Aktuelle Berechnung (o=oder, u=und) int firtstIndex = -1;//Der Index des ersten Werts aus dem Array (für eine Operation) bool? brVal1 = null;//Wert des ersten Klammerausdrucks, wenn einer gefunden wurde for (; i < exp.Length; ++i) { switch (exp[i])//Was für ein Zeichen ist an der Stelle i? { //Operatoren case 'o': case 'u': curretnExp = exp[i].ToString(); break; //Indices der Werte case '0': case '1': case '2': case '3': if (firtstIndex == -1) { //1. Operator firtstIndex = int.Parse(exp[i].ToString());//Index merken break; } else { //2. Operator > Verarbeiten bool firstVal = false; if (firtstIndex != -1) firstVal = bools[firtstIndex];//1. Operator war ein Index else firstVal = (bool)brVal1;//1. Operator war eine Klammer bool res = false; ; switch (curretnExp) { case "o": res = firstVal || bools[int.Parse(exp[i].ToString())]; break; case "u": res = firstVal && bools[int.Parse(exp[i].ToString())]; break; default: throw new ArgumentException();//Unbekannter Operator } //Werte zurück setzen; brVal1 = null; firtstIndex = -1; ++i;//Klammer zu überspringen return res;//Wert zurück geben //Ich gehe hier davon aus, das jeder Operaot in Klammern steht, nach dem Schema (WERT1 OPERATOR WERT2) } //Klammern case '(': ++i;//i um 1 erhöhen um die Klammer zu überspringen var x = Parse(exp, bools, ref i); if (brVal1 == null) { brVal1 = x; break; } else { //2. Operator bool firstVal = false; if (firtstIndex != -1) firstVal = bools[firtstIndex];//1. Operator war ein Index else firstVal = (bool)brVal1;//1. Operator war eine Klammer bool res = false; ; switch (curretnExp) { case "o": res = firstVal || x; break; case "u": res = firstVal && x; break; default: throw new ArgumentException();//Unbekannter Operator } //Werte zurück setzen; brVal1 = null; firtstIndex = -1; ++i;//Klammer zu überspringen return res;//Wert zurück geben } case ')': case ' ': break;//Leerzeichen und Klammer zu ignorieren } } throw new ArgumentException(); //! Fehler, weil eigentlich beim 2. Operator zurück gesprungen werden sollte }
Der Code ist noch weit ausbaufähig, aber es ist ein Ansatz. In meinen 4 kurzen Tests hat es soweit funktioniert. Natürlich kannst du den Code noch optimieren und verbessern. Je anchdem was du alles machen möchtest, brauchst du auch noch weitere Operatoren.
Bisher versteht der Parser nur or und and. Des weiteren verlangt der Code, das jeder Operator mit seinen Werten eingeklammert ist, also (1 or 2) Doppelte Klammern ((1)) sind nicht erlaubt und Leerzeichen werden ignoriert. Wie gesagt, meine Tests zeigten keine Fehler, aber der Code ist auch noch nicht sehr Komplex oder ausgereift.Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.- Als Antwort markiert Stefan (sb) Sonntag, 9. März 2014 15:30
-
Hi Sefan,
kein Problem. Wenn deine Abfrage abfrage beleibig Komplex werden soll wirst du dir da Wohl selber einen Praser bauen müssen für einfache Fälle hat die Enum schon einen.
Wenn es bei deine oben gegebenen Fall bleibt (und verknüpfung gefolgt von oder), sollte es reichen die Werte Komma Seperiert in die DB zu speichern.
Mal als Beispiel
Dein Ausdruck mit den Flags in Binerer Darstellung.
(0001 && 0010) || (0100 && 1000) => 3,12 (Hoff mal das ist auf die schnelle im Kopf richtig).
Das komma steht dann immer für ein oder und in den Int Werten sind die Flags gespeichert.
MFG
Björn