Taschenrechner programmieren mit C# der die Eingabe aus einer Zeile lesen kann?
Ich habe im Moment einen der nur in dieser Art funktioniert :
5
*
5
10
Also ein normaler Consolen Taschenrechner, aber ich brauche einen der so Rechnen kann: 5+5 10 also in einer Zeile. Ich krieg es nicht gebacken, mein Code:
using System;
namespace ConsoleApplication2 { public enum Rechenoperation { Minus,Plus,Division,Multiplikation, Unbekannt } internal class Program { public static void Main(string[] args) { var zahl1 = AskZahl(); var rechenoperation = AskforRechenoperation(); var zahl2 = AskZahl(); int? ergebnis = null; switch (rechenoperation) { case Rechenoperation.Minus: ergebnis = zahl1.Value - zahl2.Value; break; case Rechenoperation.Plus: ergebnis = zahl1.Value + zahl2.Value; break; case Rechenoperation.Division: ergebnis = zahl1.Value / zahl2.Value; break; case Rechenoperation.Multiplikation: ergebnis = zahl1.Value * zahl2.Value; break; case Rechenoperation.Unbekannt: break; default: throw new ArgumentOutOfRangeException(); }Console.Out.WriteLine(ergebnis); Console.ReadKey(); }
private static Rechenoperation AskforRechenoperation()
{
Console.WriteLine("");
var eingabe = Console.ReadLine();
if (eingabe.Contains("-"))
{
return Rechenoperation.Minus;
}
if (eingabe.Contains("*"))
{
return Rechenoperation.Multiplikation;
}
if (eingabe.Contains("+"))
{
return Rechenoperation.Plus;
}
if (eingabe.Contains("/"))
{
return Rechenoperation.Division;
}
return Rechenoperation.Unbekannt;
}
private static int? AskZahl2()
{
Console.WriteLine("");
var eingabe = Console.ReadLine();
if (int.TryParse(eingabe,out var zahl))
{
return zahl;
}
return null;
}
}
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();
}
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.
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
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" ^^).
Der hilft mir aber leider nicht sehr da ich schon Commands brauche die meinen Kenntnissen entsprechen, trotzdem danke!
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();
}
}
}
}}
So, da isser: https://drive.google.com/open?id=1sEbgrTVcAgst8FCSjfZWiaxptl_aWcuK
Aber Achtung: Der Code ist ziemlich undokumentiert (eigentlich eher gar nicht dokumentiert ^^) und vermutlich auch nicht gerade der effizienteste. Ausserdem hat das Teil zwar ein paar Ansätze um auch Mengenoperationen durchführen zu können, aber das ist bestenfalls halbfertig. Aber der Rest funktioniert soweit. ^^
Danke für den Code, ich werde mir den mal anschauen (:
Nö... 2Zeilen Netto: