Windows Forms Taschenrechner: Komma-Problem?
Hallo ich erstelle derzeit einen Taschenrechner in Windows Forms.
Ich bin eigentlich fertig mit dem Taschenrechner, bin aber leider jetzt am Schluss auf ein Problem gestoßen, was ich nicht gelöst bekomme:
Wenn ich als Aufgabe 12,4 + 3 eingebe, kommt 127 raus. Ich verstehe aber einfach nicht warum. Es hat die ganze Zeit funktioniert und plötzlich nicht mehr. Vielleicht habe ich ja unbewusst etwas geändert.
Hier der Codeabschnitt, der etwas mit dem Komma zu tun hat (ich kann leider nicht den gesamten Code einfügen, da 500 Zeilen -> erweiterter Taschenrechner):
Imports System.Globalization
Imports System.Text.RegularExpressions
Public Class Form1
Public Property zahl As String = ""
Public Property calc As String = ""
Dim input As String = ""
Private Function GetDezimalTrennzeichen() As String
Return CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
End Function
Private Sub bcomma_Click(sender As Object, e As EventArgs) Handles bcomma.Click
tb.Text += GetDezimalTrennzeichen()
End Sub
Private Sub bsolve_Click(sender As Object, e As EventArgs) Handles bsolve.Click
' ...
Dim input As String = tb.Text
input = input.Replace(",", ".")
' ...
End Sub
Private Function EvaluateExpression(expression As String) As Double
' ...
Dim sqrtRegex As New Regex("sqrt\(([^()]+)\)")
While sqrtRegex.IsMatch(expression)
input = sqrtRegex.Replace(input, Function(match)
Dim innerExpression As String = match.Groups(1).Value
Dim result As Double = EvaluateExpression(innerExpression)
If result >= 0 Then
Return Math.Sqrt(result)
Else
' Wenn das Ergebnis negativ ist, wird eine Exception ausgelöst
Throw New ArithmeticException("Negatives Ergebnis")
End If
End Function)
End While
' ...
End Function
Danke schon einmal.
Der Fehler wird wohl im EvaluateExpression irgendwo anders sein, leider hast du den nicht gepostet. PS: Der Regex hat bei sqrt(3*(2+2)) ein Problem.
Hallo. Ja leider ist der EvaluateExpression zu groß zu posten. Was genau ist denn am Regex falsch ?
Der RegEx geht bei verschachtelten Klammern schief, weil "alles außer Klammern" und danach Klammer zu nicht erfüllt ist. https://pastebin.com/ und Link hier posten.
1 Antwort
Setze mal einen Haltepunkt im ParseExpression bei
IfDouble.TryParse(part, NumberStyles.Any, CultureInfo.InvariantCulture, num)Then
numbers.Add(num)
und schaue da mal, ob part oder danach num die richtigen Werte beinhalten. Ansonsten schaue nochmal nach dem Parametern da.
Edit:
Habe meinen alten PHP Parser wiedergefunden, ich hatte das damals rekursiv gemacht. Beschreibung (Da der Editor hier nicht mehrfach einrücken kann, als Quelltext formatiert, bitte die merkwürdigen Farben ignorieren):
function func mit Parameter name (string) und value (double), Rückgabewert double zur Behandlung von Funktionen
- Wenn name='sqrt' gebe sqrt(value) zurück
- ...
Funktion parse mit Parameter ex (string) und Rückgabewert double
- werfe alle Leerzeichen in ex weg
- wenn ex leer, gebe 0 zurück
- wenn ex mit "(" beginnt und mit ")" endet, rufe parse mit dem
Inhalt der Klammer als Parameter auf und gib das zurück
- Wenn ex auf ^(\[a-z\]+)\\((.\*)\\)$ matcht (also irgendein
Funtionsname am Anfang, dann Klammer auf, am Ende Klammer zu),
dann rufe die funktion func auf, mit dem Funktionsnamen als
ersten Parameter und dem Rückgabewert von parse(Inhalt der
Klammer) als 2. Parameter
- Für alle Operatoren, also -,+,\*,/,^ etc, von niegrister zu
höchster Priorität, Laufvariabel Op
- Setze Klammerzähler auf 0
- Für i=0 bis Anzahl der Zeichen von ex -1
- setze c auf zeichen von ex an der Stelle i
- Wenn c ( ist, erhöhe Klammerzähler und setze Schleife fort (continue)
- Wenn c ) ist, vermindere Klammerzähler und setze Schleife fort
- Wenn c gleich Op (aktuellem Operator) und Klammerzähler ist 0:
- ex am operator in links und rechts splitten
- Wenn Op + ist, gebe parse(links)+parse(rechts) zurück
- Wenn Op - ist
- Wenn das - das erste Zeichen ist (i==0) oder das
Zeichen vor i ein Operator oder e ist, dann weiter (continue)
(um - als Vorzeichen auszusondern)
- gebe parse(link)-parse(rechts) zurück
- usw. für die anderen Operatoren
- gebe den Ausdruck als Double zurück
(Hier kann es nur noch eine Zahl sein. Wenn nicht, stimmt die
Syntax nicht und es ist ein Fehler.)
Das Ganze als PHP-Code:
function funct(string $name, float $value):float {
switch($name) {
case 'sqrt': return sqrt($value);
case 'pi' : return pi();
// weitere
default: echo "Illegal funczion: $name\n";
}
return 0;
}
function parse(string $ex):float {
$ex = str_replace(' ','', $ex);
if (empty($ex)) return 0;
if ((substr($ex, 0, 1)=='(') && (substr($ex, -1,1)==')'))
return parse(substr($ex, 1, strlen($ex)-2));
if (preg_match("/^([a-z]+)\((.*)\)$/", $ex, $m))
return funct($m[1], parse($m[2]));
$ops =['+','-','*','/','^'];
foreach($ops as $op) {
$kk=0;
for ($i=0;$i<strlen($ex);$i++) {
$c=substr($ex, $i, 1);
if ($c=='(') { $kk++;continue;}
if ($c==')') { $kk--;continue;}
if (($c==$op) && ($kk==0)) {
$left = substr($ex, 0, $i);
$right = substr($ex, $i+1);
switch($op) {
case '+': return parse($left)+parse($right);
case '-': {
if (($i==0) || (strstr('+-*/^e', substr($ex, $i-1, 1))!==false)) continue;
return parse($left)-parse($right);
}
case '*': return parse($left)*parse($right);
case '/': return parse($left)/parse($right);
case '^': return pow(parse($left),parse($right));
}
}
}
}
return floatval($ex);
}
wenn ich zum beispiel eingebe : 12 + 3 durchläuft er alle regeln sowie die For schleifen wie er es eigentlich machen sollte.
Naja, das wird bei vorher bei addSubRegex.IsMatch(input) schon verwurstet, schaue mal da nach, ob das Double.Parse da evtl. ein Problem mit dem "." hat und du dem auch dieses CultureInfo.InvariantCulture übergeben musst
wenn ich dort einen haltepunkt setzte, die Anwendung starte und zum beispiel eingebe : 1,2 + 3,4 springt er direkt zu
IfDouble.TryParse(part, NumberStyles.Any, CultureInfo.InvariantCulture, num)Then
numbers.Add(num)
dann steht bei part direkt 46 und bei num 0