Laden...

[erledigt] StringToBool - Parser

Erstellt von jreusch vor 16 Jahren Letzter Beitrag vor 8 Jahren 5.316 Views
jreusch Themenstarter:in
296 Beiträge seit 2007
vor 16 Jahren
[erledigt] StringToBool - Parser

Tag zusammen.

wie schon der Titel beschreibt suche ich einen StringToBool-Parser.
Die Sufu, sowie Google haben mir keine nützlichen Ergebnisse geliefert.

Ziel ist einen String im Format :


string funktion = "true&&false||true";

eben in einen bool zu parsen.

Demnach sollte die gesuchte Methode true zurückliefern.

Er sollte boolsche Ausdrücke wie ( && , || , ^ , ! ) beherrschen, sowie Klammern beachten.

  • Gibt es da schon eine Klasse für?
  • Hat jemand sowas vielleicht schon umgesetzt und kann mir helfen?

Wenn beides nicht zutrifft hätte ich gerne einen Denkanstoss, wie man so etwas umsetzen könnte?

Danke schonmal im vorraus 🙂

Gruß

2.921 Beiträge seit 2005
vor 16 Jahren

warum siehst du nicht bei Funktionsplotter nach und passt dir die eval funktion so an, daß sie mit booleschen ausdrücken umgehen kann. dann löst der compiler für dich die ausdrücke.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

jreusch Themenstarter:in
296 Beiträge seit 2007
vor 16 Jahren

Hi,
vielen Dank für die schnelle Antwort.

Das Projekt ist jedoch nicht lauffähig. Ebenfalls vermisse ich die Methode Eval().

Hat sonst jemand Links,Tips,Ideen oder Anregungen?

Eigentlich kann das doch gar nicht so schwer sein... steh nur am Schlauch 🙂

Gruß

jreusch Themenstarter:in
296 Beiträge seit 2007
vor 16 Jahren

Hallo,
auch wenn ich langsam nervig werde muss ich leider nochmal stören.

Hab mich nun heute etwas ausführlicher mit der Angehensweise eines Parsers beschäftigt und hab schriftlich was geplant.

Mein Problem ist es jetzt noch das auch wirklich umzusetzen...
...lange Rede kurzer Sinn:


string funktion = "1&&0||!0*1||0";

würde zerlegt werden in folgenden Baum:

Diesen Baum würde eine rekursive Funktion nach und nach durchforsten.
Schema:

Bei mir hängts nun schon daran den String dynamisch in diesen Baum zu zerlegen.
Denke mal die Funktion
'bool Rechne(string strVar)'
würde ich noch auf die Reihe bekommen.

Und wieder mal bettel ich um Hilfe 🙂
Wie zerleg ich das am besten?

Gruß

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo myUnderTakeR,

das Parsen kannst du doch genauso rekursiv machen.

Du nimmst einen String und teilst ihn bei dem "obersten" Operator in zwei Teile. Der "oberste" Operator ist das erste && und wenn es das nicht gibt, das erste || im String. Nach dem Teilen machst du für die Teilstrings rekursiv weiter.

Not behandelst du erst, wenn das ! am Anfang des Strings steht und der Rest des Strings keinen Operator mehr enthält.

Das beschriebene ist für den Fall ohne Klammern.

Wenn Klammern vorkommen dürfen, dann musst du den String innerhalb der Klammern solange als genau einen Operanden betrachten und Operatoren darin ignorieren, bis die öffnende Klammer am Anfang des String und die zugehörigen schließende Klammer am Ende des Strings steht. In dem Moment kannst du die beiden Klammern weglassen und rekursiv weiter machen.

herbivore

jreusch Themenstarter:in
296 Beiträge seit 2007
vor 16 Jahren

Hallo herbivore,
super Hilfestellung!

Habs jetzt bis auf ein Problem soweit auf die Reihe bekommen.

Wenn ich auf meinen String


"1*(1+0)".Split('+');

anwende teilt er mir die Klammer natürlich auch direkt mit auf.

Wie bringe ich ihm am besten bei, dass er nur teilen soll, solange die teilende Funktion von keiner Klammer umschlossen wird?

Hier mal die Funktion im momentanen Status.
Hoffe das entspricht einem einigermaßen ordentlichen Programmierstil 🙂

  • -> Und
  • -> Oder
    / -> Negierung

public string parseBool(string strFunktion)
        {
            if (strFunktion.StartsWith("(")
                && strFunktion.EndsWith(")"))
            {
                return parseBool(strFunktion.Substring(1, strFunktion.Length - 2));
            }


            if (strFunktion.Contains("+"))
            {
                foreach (string myStr in strFunktion.Split('+'))
                {
                    if (parseBool(myStr) == "1")
                        return "1";
                }
                return "0";
            }
            
            if (strFunktion.Contains("*"))
            {
                foreach (string myStr in strFunktion.Split('*'))
                {
                    if (parseBool(myStr) == "0")
                        return "0";
                }
                return "1";
            }
            
            if (strFunktion.Contains("/"))
            {
                if (strFunktion == "/0")
                    return "1";
                else
                    return "0";
            }
             
            return strFunktion;
        }

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo myUnderTakeR,

Wie bringe ich ihm am besten bei, dass er nur teilen soll, solange die teilende Funktion von keiner Klammer umschlossen wird?

so eine Methode musst du dir selbst schreiben, indem du Zeichen für Zeichen durchgehst und dabei die Klammerebenen mitzählst und immer nur teilst, wenn die Klammerebene 0 ist.

herbivore

jreusch Themenstarter:in
296 Beiträge seit 2007
vor 16 Jahren

Jopp Danke.
Geht jetzt soweit hoffentlich alles fehlerfrei.


        public string parseBool(string strFunktion)
        {
            if (strFunktion.StartsWith("(")
                && strFunktion.EndsWith(")"))
            {
                return parseBool(strFunktion.Substring(1, strFunktion.Length - 2));
            }


            if (myContains(strFunktion,'+'))
            {
                foreach (string myStr in mySplit(strFunktion, '+'))
                {
                    if (parseBool(myStr) == "1")
                        return "1";
                }
                return "0";
            }

            if (myContains(strFunktion, '*'))
            {
                foreach (string myStr in mySplit(strFunktion, '*'))
                {
                    if (parseBool(myStr) == "0")
                        return "0";
                }
                return "1";
            }

            if (myContains(strFunktion, '/'))
            {
                if (strFunktion == "/0")
                    return "1";
                else
                    return "0";
            }
             
            return strFunktion;
        }

        private bool myContains(string inString, char containChar)
        {
            int klammerEbene = 0;

            foreach (char myChar in inString.ToCharArray())
            {
                if (myChar == '(')
                    klammerEbene++;
                else if(myChar == ')')
                    klammerEbene--;

                if (myChar == containChar && klammerEbene == 0)
                    return true;
            }
            return false;
        }

        private string[] mySplit(string myString, char splitter)
        {
            ArrayList splits = new ArrayList();
            char[] myCharArr = myString.ToCharArray();


            int klammerEbene = 0;

            string addStr = string.Empty;
            for (int i = 0; i < myCharArr.Length; i++)
            {
                if (myCharArr[i] == '(')
                    klammerEbene++;
                else if (myCharArr[i] == ')')
                    klammerEbene--;


                if (myCharArr[i] != splitter || klammerEbene > 0)
                    addStr += myCharArr[i].ToString();
                else
                {
                    splits.Add(addStr);
                    addStr = string.Empty;
                }
            }

            if (!string.IsNullOrEmpty(addStr))
                splits.Add(addStr);



            string[] ret = new string[splits.Count];

            for (int i = 0; i < splits.Count; i++)
                ret[i] = (string)splits[i];

            return ret;
        }

A
51 Beiträge seit 2014
vor 8 Jahren

Du nimmst einen String und teilst ihn bei dem "obersten" Operator in zwei Teile. Der "oberste" Operator ist das erste && und wenn es das nicht gibt, das erste || im String. Nach dem Teilen machst du für die Teilstrings rekursiv weiter.

Da ich gerade damit zu tun habe, hier eine mögliche Implementierung:


        private bool ParseAlgebraString(string _str)
        {
            bool _Result = false;
            if(_str.Contains("OR"))
            {
                var _Parts = _str.Split(new string[] { "OR" }, 2, StringSplitOptions.None);
                _Result = ParseAlgebraString(_Parts[0]) || ParseAlgebraString(_Parts[1]);
            }
            else if(_str.Contains("AND")) 
            {
                var _Parts = _str.Split(new string[] { "AND" }, 2, StringSplitOptions.None);
                _Result = ParseAlgebraString(_Parts[0]) && ParseAlgebraString(_Parts[1]);
            }
            else if(_str.Contains("NOT")) 
            {
                var _Parts = _str.Split(new string[] { "NOT" }, 2, StringSplitOptions.None);
                _Result = !ParseAlgebraString(_Parts[1]);
            }
            else
            {
                _Result = XXX(_str.Trim());
            }

            return _Result;
        }

Wobei Funktion XXX(string s) einen boolschen Wert abhängig des übergebenen Parameters zurückgibt.
Außerdem verwende ich anstelle von && ein AND und || ein OR. Schlüsselwörter können aber beliebig ersetzt werden.

Vielleicht hilft's jemandem.

Die Grenzen meiner Sprache bedeuten die Grenzen meiner Welt - Tractatus 5.6, Ludwig Wittgenstein

4.942 Beiträge seit 2008
vor 8 Jahren

Hallo adm1n,

auch wenn der Originalbeitrag schon etwas älter ist, aber da du ihn wieder hervorgeholt hast, will ich dann doch auf meinen Parser für mathematische Formeln hinweisen, da dieses "String auseinanderfrickeln" einer der Gründe dafür war, meinen Parser hier zu veröffentlichen (der LogicParser entspricht dann den Anforderungen dieses Beitrags).

Deine Methode hat z.B. den Fehler, daß "true NOT false" erfolgreich geparst wird, obwohl es kein gültiger boolscher Ausdruck ist.

A
51 Beiträge seit 2014
vor 8 Jahren

Danke für den Hinweis. Der Parser ist bei meiner Recherche an mir vorbei gegangen 😃

Die Grenzen meiner Sprache bedeuten die Grenzen meiner Welt - Tractatus 5.6, Ludwig Wittgenstein