Bestimmte Befehle in einer Datei ausführen

Met456

Grünschnabel
Gute Tag, es ist mein 1. Tag hier im Forum. Ich benutze es schon Länger als Gast und bin jetzt bei einer stelle angekommen wo ich eure Hilfe brauche. Ich wollte mit C# auf eine datei zugreifen wo bsw if oder foreach gefehle drin stehen und die ausführen.
Ich versuch mal ein Beispiel zu erstellen

Textdatei:
Code:
if("23" == "09.02"){
echo "Richtig";
}
else
{
echo "Falsch";
}

Das soll dann so ausgeführt werden das dann später nur Richtig oder Falsch bleibt und die befehle verschwinden.

Ich Dachte mir das dass tool die Textdatei öffnet es ließt und die befehle ebend ausführt und als string dann den rest ausgibt(Richtig oder Falsch)
 

saftmeister

Nutze den Saft!
Hallo,

ich hab C# schon lang nicht mehr gemacht, nur wenig gelernt und ziemlich viel davon schon vergessen ;-)

Aber spontan fällt mir die Klasse "Compiler" ein, mit der man das bewerkstelligen könnte:

http://msdn.microsoft.com/en-us/library/microsoft.csharp.compiler(v=vs.85).aspx

Sie bietet die Methode compile(), allerdings sehe ich nicht, ob mit string[] Dateien oder Source-Code gemeint ist. Diesbezüglich wirst du vllt. noch weiter recherchieren müssen.

Und wie man da das Ergebnis zurück bekommt, hmm, keine Idee. Aber vielleicht bringt es dich trotzdem weiter.
 

Harrier

Erfahrenes Mitglied
Erstmal: Das Thema gehört in das .NET-Forum.

Also die Compiler-Klasse wäre evtl. eine Möglichkeit, wenn deine Text-Datei C#-Code enthält. Da dies hier eher nicht der Fall zu sein scheint, bliebe die Möglichkeit einen eigenen Parser zu schreiben (falls du eine begrenze Menge an Operationen in dem Textfile hast und eine strenge Syntax) oder eine Bibliothek zu suchen (falls du eine verbreitete Programmiersprache in dem Textfile verwendest, könnte es da ggf. was geben).

Falls du selbst einen Parser schreiben willst, hast du im Prinzip zwei Möglichkeiten:
1) du setzt dich mit kontextfreien Grammatiken auseinander und machst es "richtig" oder
2) du versuchst es direkt

Falls du wirklich nur if/else mit einfachen Vergleichsoperatoren hast (<, >, <=, >=, ==, etc.) und sonst nur echo brauchst, könntest du es direkt versuchen.

Dann kann die Funktion in etwa so funktionieren:
Du gehst das File so lange durch, bis du ein if, ein else oder ein echo findest.
Wenn du ein if findest, prüfst du ob die Bedingung erfüllt ist (da dürfte String.Split praktisch sein), falls ja, übergibst du den folgenden Block z.B. rekursiv wieder derselben Funktion. Ansonsten setzt du dir ein Flag, dass du auf ein else wartest.
Wenn du ein else triffst, und dein Flag gesetzt ist, übergibst du den else-Block rekursiv der Funktion. Ansonsten überspringst du den Block.
Wenn du ein echo triffst, gibst du eben den String aus.

Damit das nicht zu sehr ausufert, solltest du die Syntax möglichst begrenzt halten. Zum Beispiel würde ich bei if/else immer { } verlangen, auch wenn nur ein Statement zu parsen ist.

Falls deine Sprache deutlich mehr können muss, wirst du kaum drum 'rum kommen, das Ganze etwas systematischer anzugehen - das ist aber aufwändig. Vielleicht kannst du ja doch auf Script-Sprachen ausweichen, für die es eine Bibliothek gibt?
 

Met456

Grünschnabel
Hallo, danke erstmal dafür das ihr geantwortet habt. Die Compiler-Klasse hilft mir da leider nicht weiter.
@ Harrier
Es soll nur bestimmte funktionen zu verfügung stehen wie bsw if()
else währe nicht so wichtig da man es auch anders machen kann. Ich habe das Ganze wie du es beschrieben hast leider nicht verstanden. Ich erkläre mal nochmal wie ich es meinte


Textdatei:
if(datumheute == "09.02.2014")
{
echo "Richtig";
}


so soll es in einer textdatei drin sein. Natürlich nicht nur 1 if sondern mehrere

Textdatei danach:
Richtig



das heißt die befehle soll man danach auch nicht sehen
 

Harrier

Erfahrenes Mitglied
Also, vielleicht hilft dieses Gerüst etwas beim Verständnis. Ich habe das Abarbeiten der eigentlichen Befehle jetzt in verschiedene Funktionen ausgelagert, sodass das Konzept etwas deutlicher wird.

Code:
class Parser
{
	private int lineNumber = 0;
	private string[] code;
	
	public void load(string file) { ... }

	private void parse()
	{
		// ende?
		if(lineNumber >= code.Length)
			return;
		
		string line = code[lineNumber];
		line.trim();
		
		// echo?
		if(line.StartsWith("echo"))
			execEcho(line);
		// if?
		else if(line.StartsWith("if("))
		{
			if(!execCompare(line))
			{
				// if-Block nicht ausführen
				skipBlock();
			}
		} else if(line.equals("{") || line.equals("}")); 	// { und } einfach überspringen.
		
                // nächste Zeile
		lineNumber++;
		parse();
	}
	
	private execEcho(string line) { ... }
	
	private execCompare(string line) { ... }
	
	private skipBlock() { ... }
}

Die load-Methode läd dein File Zeile für Zeile in das code-Array.
Dann rufst du parse() auf. Die Methode nimmt sich nun Zeile für Zeile vor (bei jedem Aufruf eine Zeile), bis es keine mehr gibt.

Dann wird geprüft, ob die Zeile eine if-Anweisung oder ein echo enthält. Enthält es ein echo, wird execEcho aufgerufen.
Bei if ist die Sache ein klein bisschen komplizierter. Hier muss erstmal geprüft werden, ob die Bedingung überhaupt erfüllt ist. Das wird durch execCompare() gemacht. Ist die Bedingung nicht erfüllt, muss der Block übersprungen werden. Das macht skipBlock(). Ansonsten kann einfach die nächste Zeile ausgewertet werden.

execEcho ist nun nicht mehr so schwer. Der Parameter line, der dabei übergeben wird, sollte ja in etwa so aussehen:
echo "Richtig";
skipBlock ist ganz einfach: Du erhöhst lineNumber einfach so lange, bis code[lineNumber] gleich "}" ist.

Bei execCompare würde ich dir raten, erstmal das if( und die Klammer ganz hinten loszuwerden. Dann solltest du herausfinden, welchen Vergleichsoperator du brauchst (== oder <= oder was auch immer). Dies ist einfach, wenn == nicht auch in deinem String vorkommen kann, also wenn
if(lala == "x==y")
nicht erlaubt ist. Wenn du dann an deinem Operator den string splittest, bekommst du die beiden Dinge, die du vergleichen möchtest.

Natürlich muss die Syntax dabei genau stimmen. Also es muss if heißen, nicht IF. Die Befehle müssen am Anfang der Zeile stehen (bzw. es dürfen nur Leerzeichen davor sein). { und } müssen in einer eigenen Zeile sein. Und so weiter... Außerdem würde auch so etwas gehen:
if(heute=="abc")
echo "Richtig";
}

All diese Dinge kann man natürlich auch noch abfragen, aber das wird für das Beispiel zu kompliziert.
 

Met456

Grünschnabel
Danke dir!
du hast mich auf eine idee gebracht und das hat wirklich geklappt


Code:
                int ok = 0;
                if (m.Contains("if(") && m.Contains("!="))
                {
                    ok = 1;
                    var regex = new Regex("\"(.*?)\"");
                    var match = regex.Match(m);
                    var regex2 = new Regex("\\((.*?) !=");
                    var match2 = regex2.Match(m);
                    var regex3 = new Regex("{(.*?)}");
                    var match3 = regex3.Match(m);
                    if (match2.Groups[1].Value != match.Groups[1].Value)
                    {
                        mx += match3.Groups[1].Value + Environment.NewLine;
                    }
                }
                
                if (m.Contains("if(") && m.Contains("=="))
                {
                    ok = 1;
                    var regex = new Regex("\"(.*?)\"");
                    var match = regex.Match(m);
                    var regex2 = new Regex("\\((.*?) ==");
                    var match2 = regex2.Match(m);
                    var regex3 = new Regex("{(.*?)}");
                    var match3 = regex3.Match(m);
                    if (match2.Groups[1].Value == match.Groups[1].Value)
                    {
                        mx += match3.Groups[1].Value + Environment.NewLine;
                    }
                }
                
                if (m.Contains("print("))
                {
                    ok = 1;
                    var regex = new Regex("print\\(\"(.*?)\"\\);");
                    var match = regex.Match(m);
                    mx += match.Groups[1].Value + Environment.NewLine;
                }
 

Harrier

Erfahrenes Mitglied
Richtig. Regular Expressions sind in jedem Fall nochmal eleganter als mit splits zu arbeiten.

Wenn's jetzt funktioniert, solltest du das Thema noch auf erledigt setzen.