Taschenrechner programmieren mit C# der die Eingabe aus einer Zeile lesen kann?

3 Antworten

Dafür würde ich einen kleinen Parser basteln. (Geht auch mit "Regulären Ausdrücken", aber das wäre mit Kanonen auf Spatzen geschossen, außerdem sind Reguläre Ausdrücke nicht besonders flexibel.)

Kennst du schon Listen? Ich würde eine List<String> anlegen

using System.Collections.Generic;

// ...

    var inputAsLines = New List<String>();

und dann das Eingabestring zeichenweise durchgehen, Leerzeichen überspringen und bei jedem Wechsel der Zeichenart (Zahlzeichen (Ziffer, Komma, Punkt); Operatorzeichen (+-*/); sonstige) ein neues String anfangen.

Danach kann man die Strings als Eingabezeilen behandeln.

Du könntest natürlich auch jedes String sofort auswerten, aber "Iterator-Methoden" sind für den Anfang zu unübersichtlich, denke ich.

    const Char[] operatorChars = new Char[] {'+', '-', '*', '/'};
    
    var currentCharCategory = "Ignore";  // mit nicht-ausgewertetem Trennzeichen anfangen
      // ein enum waere hier sinnvoller
      // Char.GetUnicodeCategory() liefert leider keine direkt brauchbaren Unterscheidungen
    var previousCharCategory = currentCharCategory;
    
    var sb = New StringBuilder(inputString.Length);
    
    foreach (char c in inputString) {
      if (Char.IsNumeric(c) || Char.IsPunctuation(c)) {
        currentCharCategory ="Number";
      } else if (operatorChars.Contains(c)) {
        currentCharCategory = "Operator";
      } else {
        currentCharCategory = "Ignore";
      }
      
      if (currentCharCategory != previousCharCategory) {
        if (sb.Length > 0) {
          inputAsLines.Add(sb.ToString());
          sb.Clear();
        }
        previousCharCategory = currentCharCategory ;
      }
    }
    
    if (sb.Length > 0) {
      inputAsLines.Add(sb.ToString());
      sb.Clear();
    }
    
Woher ich das weiß:Berufserfahrung – Software-Entwickler

C# kennt leider nicht wie J(ava)Script eine Eval-Funktion.

Es gibt Diverse Tricks um dennoch eine solche Funktion zu basteln.

Es wäre möglich eine JScript.Net -Dll zu erstellen un die darin enthaltene Eval-Funktion aufzurufen.

Ich habe mich in meinem Beispiel für die Compute-Methode der DataTable-Klasse entschieden.

simplecalc.cs

using System;
namespace simpleEvaluator
{
class Program
{
    static Double Eval(String expression)
    {
        System.Data.DataTable table = new System.Data.DataTable();
        return Convert.ToDouble(table.Compute(expression, String.Empty));
    }
    static void Main(string[] args)
    {
        string allArgs="";
        if (args.Length == 0)
        {
            Console.WriteLine(System.AppDomain.CurrentDomain.FriendlyName+"Please enter a Formula to commandline.");
            Console.WriteLine("Help: "+System.AppDomain.CurrentDomain.FriendlyName+"  (3+2)*5");
        }
        else
        {
            for (int i = 0; i < args.Length; i++)
            {
                allArgs += args[i]; //alle Kommandozeilenargumente  zu  einen String zusammenfassen
            }
            //Console.WriteLine("Your Formula:");
            //Console.WriteLine(allArgs);
            Console.WriteLine(Eval(allArgs));
        }
    }
}}

natürlich habe ich auch eine Hybrid-C#-Batch in Petto:

simplecalc.cmd

/* 2>nul ||@cls und flink eine Zeile Prompt löschen
@echo off
mode con cols=80
for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*csc.exe"') do (
set "csc=%%v"
)
"%csc%" /out:"%~n0.exe" %0
"%~n0.exe"
echo Demo:
echo:
"%~n0.exe" 3+2
"%~n0.exe" (1+2)*3
"%~n0.exe" 5*(3+2)/7

pause
exit /b %errorlevel%

rem Die nächste Zeile ist wichtig nicht ändern!
::::C#code */
using System;
namespace simpleEvaluator
{
class Program
{
    static Double Eval(String expression)
    {
        System.Data.DataTable table = new System.Data.DataTable();
        return Convert.ToDouble(table.Compute(expression, String.Empty));
    }
    static void Main(string[] args)
    {
        string allArgs="";
        if (args.Length == 0)
        {
            Console.WriteLine(System.AppDomain.CurrentDomain.FriendlyName+"Please enter a Formula to commandline.");
            Console.WriteLine("Help: "+System.AppDomain.CurrentDomain.FriendlyName+"  (3+2)*5");
        }
        else
        {
            for (int i = 0; i < args.Length; i++)
            {
                allArgs += args[i]; //alle Kommandozeilenargumente  zu  einen String zusammenfassen
            }
            Console.WriteLine("Your Formula:");
            Console.WriteLine(allArgs);
            Console.WriteLine(Eval(allArgs));
        }
    }
}}

...etwas mehr als eine normale Batch. Das Ergebnis ist eine Exedatei. die Batch sucht sich automatisch einen c#-Compiler und und compiliert den angehängten C#-Code.

Erzesel  08.11.2019, 14:39

PS... ich vergaß:

Aufruf in der console:

simplecalc 1+3*4/(33-2)

oder

es geht auch mit Floatingpoint-Zahlen

simplecalc  6.66666+3.3333333
0

Dazu müsstest du einen "Expression-Parser/Evaluator" programmieren.

Das ist selbst in der einfachsten Fassung schon ein ziemlicher Haufen Arbeit.

Ich hab mich mal vor einiger Zeit an sowas rangegeben, ist zwar noch immer nicht ganz fertig, aber grundsätzlich läufts erstmal soweit.

Falls Interesse besteht, könnt ich dir gegen 15:00 den Code zukommen lassen (bin grad nicht zuhaus und hab ihn auch leider nicht auf meinem "Server" ^^).

ItzMarvinPl4yz 
Fragesteller
 08.11.2019, 10:58

Ja das wäre ziemlich hilfreich (:

0
Erzesel  08.11.2019, 14:28
Dazu müsstest du einen "Expression-Parser/Evaluator" programmieren.
Das ist selbst in der einfachsten Fassung schon ein ziemlicher Haufen Arbeit

Nö... 2Zeilen Netto:

System.Data.DataTable table = new System.Data.DataTable();
return Convert.ToDouble(table.Compute(expression, String.Empty));
0
Isendrak  08.11.2019, 14:35
@Erzesel

Okay, wenn man einen bereits fertigen nimmt, geht das natürlich mit minimalstem Aufwand. ^^

0
ItzMarvinPl4yz 
Fragesteller
 08.11.2019, 15:25
@Erzesel

Der hilft mir aber leider nicht sehr da ich schon Commands brauche die meinen Kenntnissen entsprechen, trotzdem danke!

0
Erzesel  09.11.2019, 12:25
@ItzMarvinPl4yz

Spätestens jetzt entspricht es Deinen Kenntnissen,denn ich habe dir dies zur Kenntnis gebracht.

Immerhin setzt Du an den Beginn deines Programms "using System;" um den namespace System einzubinden.

Ebenso kann man mit "using System.Data;" den von mir vorgeschlagenen Namespace einbinden um auf die Routinen zur Tabellencalculation zuzugreifen.

Natürlich kann man sich das Leben schwer machen und ein Monstrum programmieren, nur weil man nicht weiß das die Entwickler von Microsoft genau dies vermeiden wollen. In C# geht es ja genau darum dem Programmierer ein effizientes Werkzeug in die Hand zu legen.

Das von mir verwendete Material ist ohne etwas Herunterzuladen auf jedem Windowsrechner verfügbar. Ich habe nicht einmal VisualStudio nötig. Notepad reicht völlig. ein C#-Compiler ist auf jedem Windowsrechner unter C:\WINDOWS\Microsoft.NET\Framework\... zu finden.

@Knomle hat schon die Fehleranfälligkeit eines eigenen Parsers erwähnt. Regeln wie Punkt- vor Strichrechnung bleiben da außen vor und ein Eigenbaumonster lutscht alles einfach von links nach rechts ab.

Ich bin auch kein Super-C#-Programmierer und koche auch nur mit Wasser. Bis gestern hatte ich mich auch noch nicht mit der verwendeten Möglichkeit auseinandergesetzt. Ergo entsprach es auch nicht meinen Kenntnisstand. Immerhin habe ich die mir gebotenen Möglichkeiten genutzt um meinen Kenntnisstand zu aktualisieren.

PWolf hat hier den Namespace System.Collections.Generic eingebracht. sicher auch etwas , das Außerhalb deiner bisherigen Kenntnisse liegt.

Die Welt ist voller "Erfinder" welche enttäuscht feststellen das es das Ding , welches sie mit Schweiß und Tränen "erfunden" haben bereits gibt.

Ich hatte etwas Zeit und habe "Meinen" Consolen-Taschenrechner etwas optimiert. (Statt mich mit mit der Auswertung von Formelstrings herumzschlagen)

Er kommt ohne weltbewegende Stringoperationen aus . Dafür kann nun auch die Formel auch direkt eingegeben oder oder über eine Pipline übergeben werden. Falsche Formeln werden einfach durch eine simple Fehlerbehandlung abgefangen.

Das Ganze ist sowas von Anfängerlevel, das es schon fast wehtut .

using System;
using System.Data;
namespace simpleCalculator
{
class calculate
{
  static Double calc(String expression)
  {
    DataTable table = new DataTable();
    return Convert.ToDouble(table.Compute(expression, String.Empty));
  }
  static void Main(string[] args)
  {
    string Formula="";
    if (args.Length == 0)
    {
      Console.WriteLine("Please enter a Formula to commandline.");
      Console.WriteLine("Help: "+System.AppDomain.CurrentDomain.FriendlyName+" (3+2)*5");
      Console.WriteLine("Interactive Mode, please enter your Formula now : ");
      Formula=Console.ReadLine();
      try
      {
         Console.WriteLine(calc(Formula));
      }
      catch
      {Console.WriteLine("No valide Formula");}
      Console.ReadLine();
    }
    else
    {
      for (int i = 0; i < args.Length; i++)
      {
        Formula += args[i]; //alle Kommandozeilenargumente zu einen String zusammenfassen
      }
      try
      {
         Console.WriteLine(calc(Formula));
      }
      catch
      {
        Console.WriteLine("No valide Formula");
        Console.ReadLine();
      }
    }
  }
}}
0