[QUIZ#2] Mark (PHP)

Mark

Cinema4D
Hi Ihr Lieben!

Hm, ich fange mal klein an ;)
Wieder (wie beim Quiz zuvor) eine RegExp, die nach einem Notations-Zeichen (+-*/) gefolgt von zwei Zahlen sucht. Ein Fund wird umgestellt, mit eval() errechnet und dadurch ersetzt. Dies geschieht so lange, bis oben Gesuchtes nicht mehr vor kommt...

PHP:
<?php
echo "tutorials.de Coding-Quiz #2 - Polnischer Taschenrechner<br /><br />\n";

//	Eingabe per Html-Form 
$aufgabe = $_GET['aufgabe'];
echo '<form><input type="text" name="aufgabe" value="' . $aufgabe .'" /></form>' . "\n";

//	Leerzeichen Anfang & Ende entfernen 
$term = trim($aufgabe);

//	Doppelte Leerzeichen entfernen 
$term = preg_replace('/ +/', ' ', $term);

//	Sucht Operant gefolgt von zwei Zahlen 
$regex = '/([+|-|\*|\/]) (-?\d+\.?\d*) (-?\d+\.?\d*)/';
while ( preg_match($regex, $term, $treffer) ) {
	//	Prüft bei Division, ob Divisor = 0 
    if ($treffer[1] == '/' && $treffer[3] == 0)
		$term = "Fehler: Division durch null."; // -> Abbruch der While-Schleife 
	//	Ersetzt das Gefundene mit dessen Berechnung 
    $term = preg_replace(
		$regex . 'e',
		'eval("return ${2} ${1} ${3};")',
		$term);
}

//	Ausgabe Ergebnis
echo $term;

?>

Liebe Grüße,
Mark.
 
Hi nochmal!

... und noch mit einer kleine Erweiterung: dem umgeformten Term.
Leider mit bekannten Einschränkungen (s.u.), aber es fehlt mir momentan die Zeit um fehlendes Wissen durch Fleiß (Suchen&Probieren) zu ersetzen ;)

PHP:
<?php
////////////////////////////////////////////
//    convert_term - Teil-Terme umformen         
//    $part[]: 1=Operant 2=Term_1 3=Term_2     
function convert_subterm($part) {

    //    Klammerung bei Multiplikation und Division 
    if ($part[1] == '*' || $part[1] == '/') {
        //    Ungeklammerte Addition oder Subtraktion    
        $regex = '/(?<!\()\d ([+|-]) \d(?!\))/'; //    nicht korrekt! 
        //    Teil-Term 1 benötigt Klammerung 
        if (preg_match($regex, $part[2], $t))
            $part[2] = '(' . $part[2] . ')';
        //    Teil-Term 2 benötigt Klammerung 
        if (preg_match($regex, $part[3], $t)) {
            $part[3] = '(' . $part[3] . ')';
        }
    }
    
    //    Teil-Terme und Operant zusammensetzen 
    $convert = "$part[2] $part[1] $part[3]";
    
    //    Neuen Term markieren & Rückgabe 
    return '[' . $convert . ']';
}


////////////////////////////////////////////
//    MAIN - Polnischer Taschenrechner         
echo "tutorials.de Coding-Quiz #2 - Polnischer Taschenrechner<br /><br />\n";

//    Eingabe per Html-Form 
$input = $_GET['input'];
echo '<form><input type="text" name="input" value="' . $input . '" /></form>' . "\n";

//    Leerzeichen Anfang & Ende entfernen 
$term = trim($input);

//    Doppelte Leerzeichen entfernen 
$term = preg_replace('/ +/', ' ', $term);

//    Markierung der Zahlen als Teil-Terme 
$term = preg_replace('/(-?\d+\.?\d*)/', '[${1}]', $term);


//    Findet Operant gefolgt von zwei Teil-Termen 
//    +|-|*|/ [...] [...] 
$regex    = '/([+|-|\*|\/]) \[((?:[^[])+)\] \[((?:[^[])+)\]/';
while ( preg_match($regex, $term, $t) ) {
    //    Ersetzt Fund durch konvertierten Term 
    $term = preg_replace_callback(
        $regex,
        convert_subterm,
        $term, 1
    );
}

//    Term-Markierungen entfernen    
$term = preg_replace('/[\[|\]]/', '', $term);

//    Term berechnen & Ausgabe 
if ($term) {
    eval("\$result = $term;"); // TODO: Fehler abfangen 
    echo $term . ' = ' . $result;
//    Kein Term 
} else {
    echo 'Bitte Term eingeben.';
}
?>

Bekannte Einschränkungen:
a) Die Eingabe wird überhaupt nicht auf Korrektheit geprüft.
b) Das eval() wird nicht geprüft. Ich wusste einfach nicht wie :( So wird z.B. kein "Division by zero" abgefangen.
c) Die RegExp '/(?<!\()\d ([+|-]) \d(?!\))/' ist wohl nicht ganz korrekt: hatte einen Fall, bei dem eine Multiplikation geklammert wurde, obwohl dies nicht nötig war ... ich Depp weiß nur leider den Term nicht mehr :-(
d) ... kommt sicher noch, spätestens bei Diskussionsbeginn ;)

So, das war's von meiner Seite - diesmal nix in Coffee, verzeih, Matthias ;) -, bin schon gespannt auf die Umsetzungen von Euch anderen und vielleicht entdecke ich ja irgendwo meine verhunzte RegExp (c)) in "richtig" :)

Liebe Grüße,
Mark.
 
Hmm, wenn ich mich an den Wikipediaeintrag erinnere, wo etwa stand "Solange gucken wie man einen Operator plus zwei Operanden findet, die auswerten und gegen das Ergebnis ersetzten"... dann muss ich sagen: ziemlich direkter Ansatz =) hmm, aber ich glaub nicht so gut erweiterbar, um eigene Funktionen und Variablen, oder?
 
Hi OnlyFoo!
Hmm, wenn ich mich an den Wikipediaeintrag erinnere, wo etwa stand "Solange gucken wie man einen Operator plus zwei Operanden findet, die auswerten und gegen das Ergebnis ersetzten"... dann muss ich sagen: ziemlich direkter Ansatz =)
Na, Super, den Eintrag kannte ich nicht ... und ich dachte, mein Ansatz wäre pfiffig / innovativ ;)
hmm, aber ich glaub nicht so gut erweiterbar, um eigene Funktionen und Variablen, oder?
Da ich zunächst eigentlich nur das Ergebnis berechnen wollte, habe ich mir darüber keine Kopf gemacht. Die Erweiterung mit der Klammerung war schon nicht vorgesehen... ;)
Wenn man die RegEx weniger strikt nach "Zahlen" suchen läßt, könnte ich mir aber auch eine Version mit Variblen gut vorstellen. Bei den Funktionen müssten diese so immer zwei Parameter erhalten bzw. man müsste vorher alle Funktionen mit einem Parameter abgrasen ;)
Aber grundsätzlich: ja, sicher hast Du recht, oben beschriebener Weg ist nicht sonderlich elegant und wenig bis garnicht erweiterbar :)

Liebe Grüße,
Mark.
 
Zurück