Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Austauschen einer Case Anweisung mit einer Sinnvolleren (https://www.delphipraxis.net/208004-austauschen-einer-case-anweisung-mit-einer-sinnvolleren.html)

Mo53 26. Mai 2021 16:43

Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Hallo Leute,
Ich bin dabei ein Programm zu schreiben, was ein Menü ausgibt in dem man auswählen kann in einem vorher eingegebenem String die Operatoren in Strings umzuwandeln also + = plus etc.
Nun habe ich es mit einer Case Anweisung probiert für jeden einzelnen Operator, jedoch besteht jetzt das Problem, das die Überprüfung endet sobald ein Operator gefunden und umgetauscht wurde. Ich komme leider nicht drauf wie ich das anders erstellen kann sodass das Programm die Überprüfung für die Operatoren nicht beendet sobald eins gefunden wurde.
Würde mich sehr freuen wenn mir jemand auf die Sprünge helfen kann :-D.

Delphi-Quellcode:
{$APPTYPE CONSOLE}
{$R+,Q+,X-}

uses
  System.SysUtils;

var
 abbruch : Boolean;
 menueEingabe : Char;
 satz : String;
 laufVariable,anzahlPlus,anzahlMinus,anzahlMal,anzahlGeteilt : Word;
 plus,minus,mal,geteilt : String;

begin
  abbruch := (menueEingabe = upcase('x')) or (menueEingabe = 'x');
  plus := ' plus ';
  minus := ' minus ';
  mal := ' mal ';
  geteilt := ' geteilt ';

  repeat
    writeln('A) Satz eingeben');
    writeln('B) Anzahl Operatoren im Satz bestimmen');
    writeln('C) Operatoren in Satz ausschreiben');
    writeln('D) Alle Wörter entfernen, die keinen Operator erhalten');
    writeln('X) Ende');

  readln(menueEingabe);

  case menueEingabe of
   'A','a' : readln(satz);
   'B','b' : begin
              if length(satz) > 0 then
                 begin
                   anzahlPlus := 0;
                   anzahlMinus := 0;
                   anzahlMal := 0;
                   anzahlGeteilt := 0;
                   for laufVariable := 1 to length(satz) do
                     begin
                       case satz[laufVariable] of
                         '+' : inc(anzahlPlus);
                         '-' : inc(anzahlMinus);
                         '*' : inc(anzahlMal);
                         '/' : inc(anzahlGeteilt);
                       end;
                     end;
                    writeln(anzahlPlus,' + und ',anzahlMinus,' - und ',anzahlMal,' * und ',anzahlGeteilt,' / im Satz gefunden');
                 end
              else writeln('Eingabe ungültig!');
             end;
   'C','c' : begin
                if length(satz) > 0 then
                   for laufVariable := 1 to length(satz) do
                     begin
                        case satz[laufVariable] of
                         '+' : begin
                                delete(satz,laufVariable, 1);
                                insert(plus,satz,laufVariable);
                               end;
                         '-' : begin
                                delete(satz,laufVariable,1);
                                insert(minus,satz,laufVariable);
                               end;
                         '*' : begin
                                delete(satz,laufVariable,1);
                                insert(mal,satz,laufVariable);
                               end;
                         '/' : begin
                                delete(satz,laufVariable,1);
                                insert(geteilt,satz,laufVariable);
                               end;
                       end;
                       end;
                       writeln(satz);


             end;
   'D','d' : begin
                if length(satz) > 0 then
                 writeln('Richtig D')
                else writeln('Eingabe ungültig!');
             end;
   'X','x' : abbruch := TRUE

    else writeln('Eingabe ist ungültig!');
  end;

  until (abbruch);

  readln;
end.

Fritzew 26. Mai 2021 17:07

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Nicht geprüft, aber da Du den Satz ja veränderst würde ich das so lösen:
Also vom Ende her untersuchen deshalb anstatt einer for eine while loop
Delphi-Quellcode:
'C','c' : begin
               laufVariable := length(satz);
               while laufvariable > 0 do
                    begin
                        case satz[laufVariable] of
                         '+' : begin
                                delete(satz,laufVariable, 1);
                                insert(plus,satz,laufVariable);
                               end;
                         '-' : begin
                                delete(satz,laufVariable,1);
                                insert(minus,satz,laufVariable);
                               end;
                         '*' : begin
                                delete(satz,laufVariable,1);
                                insert(mal,satz,laufVariable);
                               end;
                         '/' : begin
                                delete(satz,laufVariable,1);
                                insert(geteilt,satz,laufVariable);
                               end;
                        end; // End case
                        dec(laufvariable);
                    end;
                   writeln(satz);

           end;

berens 26. Mai 2021 17:50

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Du hast deine Variablen nicht initialisiert.

Delphi-Quellcode:
var
 abbruch : Boolean;
 menueEingabe : Char;
begin
  abbruch := (menueEingabe = upcase('x')) or (menueEingabe = 'x');
Du weist der Variable "abbruch" beim Programmstart einen Wert zu, der von "menueEingabe" abhängt, was wiederum ebenfalls nicht initialisiert ist.

Schreibe diese Zeile (abbruch := ...) nach " readln(menueEingabe);". Dann wird in in jedem Durchlauf ermittelt, ob das Programm verlassen werden soll, oder nicht...

Alternativ zumindest die Variable richtig initialisieren, damit Abbruch:=False hat (auch nach ReadLn), denn du verwendest ja (auch) die Case-Anweisung zum Auswerten von X.

Andreas13 26. Mai 2021 18:06

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Zur Vereinfachung könntest Du
Delphi-Quellcode:
ReadLn(menueEingabe)
gegen
Delphi-Quellcode:
ReadLn(UpperCase(menueEingabe));
tauschen, dann wären die Stellen wie
Delphi-Quellcode:
'B','b' : begin
           ...
einfacher, nämlich nur
Delphi-Quellcode:
'B' : begin
           ...
Gruß, Andreas

himitsu 26. Mai 2021 19:10

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Ähhh nein?
Das ist ein VAR-Parameter, da geht keine Funktion drumrum, schon garkeine mit String, wo es aber ein Char sein soll.
Delphi-Quellcode:
menueEingabe := UpperCase(menueEingabe)[1];

// oder direkt
case UpperCase(menueEingabe)[1] of
Aber hier sehe ich eh keinen Grund das Zwanghaft kürzen zu wollen.





Zitat:

Delphi-Quellcode:
'C','c' : begin
               laufVariable := length(satz);
               while laufvariable > 0 do
                    begin
                        case satz[laufVariable] of
                         '+' : begin
                                delete(satz,laufVariable, 1);
                                insert(plus,satz,laufVariable);
                               end;
                         '-' : begin
                                delete(satz,laufVariable,1);
                                insert(minus,satz,laufVariable);
                               end;
                         '*' : begin
                                delete(satz,laufVariable,1);
                                insert(mal,satz,laufVariable);
                               end;
                         '/' : begin
                                delete(satz,laufVariable,1);
                                insert(geteilt,satz,laufVariable);
                               end;
                        end; // End case
                        dec(laufvariable);
                    end;
                   writeln(satz);

           end;

So, wem fällt auf, dass es praktisch alle 4 Fälle identisch sind, mit Ausname des Insert-Text,

Und warum überhaupt unnötig ein WHILE, anstatt einem FOR?

Delphi-Quellcode:
       for laufVariable := Length(satz) downto 1 do
                    if satz[laufVariable] in ['+', '-', '*', '/'] then
                      begin
                        delete(satz, laufVariable, 1);
                        case satz[laufVariable] of
                          '+' : insert(plus, satz, laufVariable);
                          '-' : insert(minus, satz, laufVariable);
                          '*' : insert(mal, satz, laufVariable);
                          '/' : insert(geteilt, satz, laufVariable);
                        end;
                      end;
Delphi-Quellcode:
       const ZeichenZuText: array['*'..'/'] of string = (mal, plus, '', minus, '', geteilt);

       for laufVariable := Length(satz) downto 1 do
                    if satz[laufVariable] in ['+', '-', '*', '/'] then
                      begin
                        delete(satz, laufVariable, 1);
                        insert(ZeichenZuText[satz[laufVariable]], satz, laufVariable);
                      end;
Und nun mal ganz im Ernst ...
Delphi-Quellcode:
satz := ReplaceStr('+', plus);
satz := ReplaceStr('-', minus);
satz := ReplaceStr('*', mal);
satz := ReplaceStr('/', geteilt);

// oder
for C := Low(ZeichenZuText) to High(ZeichenZuText) do
  if ZeichenZuText[C] <> '' then
    satz := ReplaceStr(C, ZeichenZuText[C]);

Mo53 26. Mai 2021 22:05

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Vielen Dank Leute, das hat mir sehr weitergeholfen:-D

Mo53 27. Mai 2021 13:05

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Ich versuche jetzt gerade für Menüpunkt D eine Anweisung zu erstellen die alle Wörter in denen kein Operator enthalten ist löscht.
Bsp.: (Gu+en Tag) wird zu (Gu+en).
Jedoch ist dies komplizierter als gedacht.
Habt iht vielleicht eine Idee?
Ich darf jedoch keine Arrays oder selbstgemachte Funktionen anwenden.

Delphi-Quellcode:
 begin
          if length(satz) > 0 then
          begin
            leerZeichen := ' ';
            laufVariable := 1;
            repeat
              for laufVariable := 1 to pos(leerZeichen, satz, laufVariable) do
              begin

                case satz[laufVariable] of
                  '+':
                    inc(anzahlPlus);
                  '-':
                    inc(anzahlMinus);
                  '*':
                    inc(anzahlMal);
                  '/':
                    inc(anzahlGeteilt);
                end;
                keinOperator := (anzahlPlus = 0) and (anzahlMinus = 0) and
                  (anzahlMal = 0) and (anzahlGeteilt = 0);
                if keinOperator then
                  delete(satz, laufVariable,
                    (pos(leerZeichen, satz, laufVariable) - 1));

              end;
            until (length(satz) = laufVariable);

          end

himitsu 27. Mai 2021 13:19

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Erst das "ganze" Wort durchgehn
und nach der Schleife wird Entschieden, ob löschen oder nicht.

Mo53 27. Mai 2021 13:41

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
@Himitsu
Ich mache das ja schon, aber ich verstehe nicht wie ich dem Programm erklären soll das es ein wort von anfang bis ende löscht.

Moombas 27. Mai 2021 14:03

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Gibt es mehrere Möglichkeiten.
Eine wäre z.B. Deinen Text bei jedem Leerzeichen zu splitten (http://www.delphibasics.co.uk/Method...s&Method=Split) und damit ein array zu befüllen.
Dann hast du ein Array in dem jedes Wort einzeln steht.
Dann das Array durchgehen und 1. mit pos() (https://www.delphipraxis.net/28411-post9.html) prüfen ob ein Operator enthalten ist und 2. wenn ja dies dem Ergebnisstring hinzufügen (Leerzeichen nicht vergessen).

dummzeuch 27. Mai 2021 15:34

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Zitat:

Zitat von Fritzew (Beitrag 1490202)
Nicht geprüft, aber da Du den Satz ja veränderst würde ich das so lösen:
Also vom Ende her untersuchen deshalb anstatt einer for eine while loop

Wobei in dem Fall auch ein for ... downto möglich wäre.

Mo53 27. Mai 2021 17:01

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
@Moombas ich darf leider keine arrays verwenden.

Jumpy 28. Mai 2021 07:58

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Du gehst mit einer schleife das wort durch und kopierst jeden buchstaben in eine zwischenvariable, stöst du dabei auf einen operator setzt du eine Boolean auf true. Kommst du an ein Leerzeichen (oder das Ende des Satzes) dann schaust du: War ein Operator drin, dann kopier das wort in eine neue Variable Ergebnis. War diese Variable zuvor nicht leer, ergänze erst ein Leerzeichen und hänge dann den Wert der Zwischenvariablen dran. Ist in der Zwischenvariablen kein Operator, dann leere sie einfach. Setzte die Boolean wieder auf False. Weiter gehts.

Moombas 28. Mai 2021 08:46

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Ich gehe davon aus, das ist hier dann Schul- oder Ausbildungsaufgabe?
Denn ansonsten macht das "darf keine Arrays verwenden" keinen Sinn.

Und Btw: 3 geteilt 5 liest sich komisch. Ich würde "geteilt durch" oder nur "durch" schreiben an deiner Stelle.

Jasocul 28. Mai 2021 10:06

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Delphi-Quellcode:
  if length(satz) > 0 then
  begin
    OPFound := False; // Boolean-Variable noch deklarieren
    Laenge := 0; // Integer-Variable noch deklarieren
    for laufvariable := length(satz) downto 1 do
    begin
      inc(Laenge);
      OPFound := CharInSet(satz[laufvariable], ['+', '-', '*', '/']) or OPFound;
      if satz[laufVariable] = ' ' then // Vergleich auf Leerzeichen
      begin
        if not OPFound then
        begin
          Delete(satz, laufvariable, Laenge);
        end;
        OPFound := False;
        Laenge := 0;
      end;
    end;

    if not OPFound then
    begin
      Delete(satz, 1, Laenge + 1); // +1 wegen des Leerzeichens
    end;
  end;
Falls du CharInSet nicht verwenden darfst, musst du dir das wieder in ein case umbauen.

Mo53 28. Mai 2021 12:03

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Zitat:

Zitat von Jasocul (Beitrag 1490309)
Falls du CharInSet nicht verwenden darfst, musst du dir das wieder in ein case umbauen.

Hättest du vielleicht ein Vorschlag dafür, ich habe CharInSet ehrlich gesagt noch nie gesehen.
:)

Moombas 28. Mai 2021 12:25

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Du kannst auch eine oder verknüpfte If-Anweisung nehmen.
Case hast du doch bereits gemacht, musst es nur noch anwenden.

Jasocul 28. Mai 2021 13:39

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Zitat:

Zitat von Mo53 (Beitrag 1490315)
Zitat:

Zitat von Jasocul (Beitrag 1490309)
Falls du CharInSet nicht verwenden darfst, musst du dir das wieder in ein case umbauen.

Hättest du vielleicht ein Vorschlag dafür, ich habe CharInSet ehrlich gesagt noch nie gesehen.
:)

Ganz ehrlich: Nein.
Du hast in den anderen Programmteilen bereits entsprechende Case-Strukturen drin. Der Umbau ist trivial. Du kannst dann sogar das "or OPFound" weglassen.
CharInSet prüft nur, ob dein aktuelles Zeichen aus dem Satz in der Menge der Operatorzeichen enthalten ist. Wenn du für jedes Operatorzeichen einen Case-Fall erstellst, bist du im Prinzip schon fertig.

Jumpy 28. Mai 2021 15:21

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Hier ist mMn aber der Lerneffekt mit einem "if" größer, ala

if (zeichen='+') or (zeichen='-') ... then
OPFound:=true;

Mo53 31. Mai 2021 09:51

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
So ich habs jetzt, das Programm läuft Prima, jedoch gibt es ein kleines Problem und zwar wenn man ins Menü ab oder ac oder generell einen Buchstaben nach a eingibt, wird trotzdem A ausgeführt, obwohl eigentlich gedacht war das er Eingabe ist ungültig ausgeben soll.
Habt ihr eine Idee?

Delphi-Quellcode:
{$APPTYPE CONSOLE}
{$R+,Q+,X-}

uses
  System.SysUtils;

var
  keinOperator, endeErreicht, operatorGefunden, leerzeichenGefunden: Boolean;
  menueEingabe: Char;
  leerZeichen: String;
  satz: String;
  laufVariable, anzahlPlus, anzahlMinus, anzahlMal, anzahlGeteilt,
  wortEnde: Word;

// Schleife zur Ausgabe des Menüs:
begin
  repeat
    writeln('A) Satz eingeben');
    writeln('B) Anzahl Operatoren im Satz bestimmen');
    writeln('C) Operatoren in Satz ausschreiben');
    writeln('D) Alle Wörter entfernen, die keinen Operator erhalten');
    writeln('X) Ende');
    readln(menueEingabe);
    writeln;

    menueEingabe := upcase(menueEingabe);

    case menueEingabe of
    // Option einen Satz einzugeben:
      'A':
        begin
          write('Satz eingeben: ');
          readln(satz);
        end;
    // Option alle Operatoren im String aufzuzählen:
      'B':
        begin
          if length(satz) > 0 then
          begin
            anzahlPlus := 0;
            anzahlMinus := 0;
            anzahlMal := 0;
            anzahlGeteilt := 0;
            for laufVariable := 1 to length(satz) do
            begin
              case satz[laufVariable] of
                '+':
                  inc(anzahlPlus);
                '-':
                  inc(anzahlMinus);
                '*':
                  inc(anzahlMal);
                '/':
                  inc(anzahlGeteilt);
              end;
            end;
            writeln(anzahlPlus, ' + und ', anzahlMinus, ' - und ', anzahlMal,
              ' * und ', anzahlGeteilt, ' / im Satz gefunden');
          end
          else
            writeln('Eingabe ungültig!');
        end;
    // Option alle Operatoren im String auszuschreiben:
      'C':
        begin
          laufVariable := length(satz);
          while laufVariable > 0 do
          begin
            case satz[laufVariable] of
              '+':
                begin
                  delete(satz, laufVariable, 1);
                  insert(' plus ', satz, laufVariable);
                end;
              '-':
                begin
                  delete(satz, laufVariable, 1);
                  insert(' minus ', satz, laufVariable);
                end;
              '*':
                begin
                  delete(satz, laufVariable, 1);
                  insert( ' mal ', satz, laufVariable);
                end;
              '/':
                begin
                  delete(satz, laufVariable, 1);
                  insert(' geteilt ', satz, laufVariable);
                end;
            end;
            dec(laufVariable);
          end;
          writeln(satz);

        end;
    // Option alle Wörter im String die keinen Operator enthalten zu löschen:
      'D':
        begin
          if length(satz) > 0 then
          begin
            laufVariable := length(satz);
            wortEnde := length(satz);
            endeErreicht := TRUE;

            while endeErreicht do
            begin
              operatorGefunden := FALSE;
              wortEnde := laufVariable;
              leerzeichenGefunden := FALSE;
              repeat
                if ((satz[laufVariable] = '+') or (satz[laufVariable] = '-') or
                  (satz[laufVariable] = '*') or (satz[laufVariable] = '/')) then
                  operatorGefunden := TRUE;

                if (satz[laufVariable] = ' ') then
                begin
                  leerzeichenGefunden := TRUE;
                  if not operatorGefunden then
                    delete(satz, laufVariable, (wortEnde - laufVariable + 1));
                end;

                if (not leerzeichenGefunden and (laufVariable = 1) and
                  not operatorGefunden) then
                begin
                  delete(satz, laufVariable, (wortEnde - laufVariable + 2));
                end;

                dec(laufVariable);
                if laufVariable = 0 then
                  endeErreicht := FALSE;
              until ((laufVariable = 0) or leerzeichenGefunden);
            end;
            writeln(satz);
          end
          else
            writeln('Eingabe ungültig!');
        end;
    end;
  until (menueEingabe = 'X');
end.

Jasocul 31. Mai 2021 11:25

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Deine Variable menueeingabe ist vom Typ char. Da passt nur ein Zeichen rein. Das Readln wird deshalb nur das erste Zeichen darin speichern können. Alles was danach kommt, wird verworfen. Wenn du deinen Fehler provozieren willst, musst du zum Beispiel "f" eingeben.

Mo53 31. Mai 2021 12:33

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Wie meinst du das mit dem provozieren ?

Jasocul 1. Jun 2021 06:27

AW: Austauschen einer Case Anweisung mit einer Sinnvolleren
 
Zitat:

Zitat von Mo53 (Beitrag 1490459)
Wie meinst du das mit dem provozieren ?

Du wolltest doch testen, ob bei einer falschen Eingabe deine Fehlermeldung erzeugt/provoziert wird. Dann nimm einfach einen(!) Buchstaben, der unzulässig ist. Warum das in deinem Programm mit mehreren Buchstaben nicht funktioniert, habe ich bereits erklärt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz