Windows Forms Taschenrechner: Komma-Problem?

iQa1x  01.08.2023, 10:29

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.

JulianOnFire 
Fragesteller
 01.08.2023, 10:40

Hallo. Ja leider ist der EvaluateExpression zu groß zu posten. Was genau ist denn am Regex falsch ?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

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);
}
JulianOnFire 
Fragesteller
 02.08.2023, 14:23

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

0
JulianOnFire 
Fragesteller
 02.08.2023, 14:29
@JulianOnFire

wenn ich zum beispiel eingebe : 12 + 3 durchläuft er alle regeln sowie die For schleifen wie er es eigentlich machen sollte.

0
iQa1x  02.08.2023, 16:46
@JulianOnFire

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

0