Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Beginner: Textverarbeitung (https://www.delphipraxis.net/191022-beginner-textverarbeitung.html)

jdiephaus 30. Nov 2016 14:13

Delphi-Version: 5

Beginner: Textverarbeitung
 
Hallo Liebe Community,
ich bin mittlerweile beim Thema Textverarbeitung angekommen. Hier mein Code:

Delphi-Quellcode:
program Textverarbeitung;
   {$APPTYPE CONSOLE} uses sysutils;
var textout,textin: Text;
    ch: Char;
begin
  Assignfile(textin,'test.in'); Assignfile(textout,'test.out');
  RESET(textin); REWRITE(textout); //Anfang textin  Erzeugt leeres textout
  while not(eof(textin)) do      //eof True wenn Dateiende
  begin
    if eoln(textin) then         //eoln True wenn Zeilenende
       begin
         writeln(textout);       //Schreibt eingelesene Zeile in textout?
         readln(textin)          //Liest nächste Zeile ein? Kein Semikolon?
       end                       //Kein Semikolon?
    else
      begin
         read(textin,ch);        //Liest nächstes Zeichen aus textin, schreibt in ch?
         write(textout,ch);      //Schreibt Zeichen aus ch in textout?
      end;
  end;
  CloseFile(textout);            //Schließt textout
  readln();
  end.
Ich verstehe die Funktionsweise noch nicht ganz :roll: Das Programm liest Text aus textin und schreibt ihn in textout. Funktioniert auch soweit.

Die Aufgabe lautet (falls ich den Code endlich genau verstehen würde):
- Es soll die Anzahl der Zeichen inkl. Leerzeichen gezählt werden
- Es soll die Anzahl der Worte gezählt werden

Ich habe jetzt schon einiges zum Thema Textverarbeitung gelesen auch hier im Forum, jedoch ist der Code da immer so fortgeschritten geschrieben das ich schon nicht mehr durchsteige. Procedure hier Procedure da :pale:

Meine Idee ist es die Anzahl von ch zu lesen die in textout geschrieben wird. ch in einen String zu schreiben und dann mit inttostr eine Integerzahl mit der Anzahl der geschriebenen Chars zu erzeugen. Klingt das soweit logisch?

Mit dem Zählen der Worte würde ich es dann ähnlich machen. Ich würde versuchen Wörter zu definieren als durch Leerzeichen (' ') oder Zeilenumbruch voneinander getrennte Strings. Macht das Sinn?

Ich hoffe ich konnte mich einigermaßen verständlich ausdrücken. Vielen Dank für eure Mühe. Ich weiß das sehr zu schätzen!

Klaus01 30. Nov 2016 14:23

AW: Beginner: Textverarbeitung
 
.. Zeilenende erkennst Du wenn ch = Carriage Return ist und das nächste Zeichen ch = Linefeed ist.
Ein Wort erkennst Du wenn einem Zeichen ein oder mehrere Leerzeichen folgen.

Grüße
Klaus

jdiephaus 30. Nov 2016 14:32

AW: Beginner: Textverarbeitung
 
Okay vielen Dank erstmal Klaus!

Wie kann ich den Status Carriage Return oder Linefeed aus ch auslesen?

Habe ich den Code (so wie ich ihn kommentiert habe) richtig verstanden?

Edit: Kann ich dafür ord(ch) nutzen? 32 ist in dem Fall ein Leerzeichen.

Klaus01 30. Nov 2016 14:44

AW: Beginner: Textverarbeitung
 
Hallo,

in einer Ascii Tabelle nachschauen -> http://www.torsten-horn.de/techdocs/ascii.htm
LF = #10
CR = #13

Grüße
Klaus

Jumpy 30. Nov 2016 14:49

AW: Beginner: Textverarbeitung
 
So wie du den Code planst brauchst du das mMn gar nicht wissen. Immer wenn ein eoln war, ausser beim letzten mal, müsste doch ein neues Wort sein, wenn man jetzt mal davon ausgeht, dass es keine Silbentrennung im Text gibt und Worte die ohne Silbentrennung in der nächsten Zeile weiter gehen.

Dann bräuchtest du nur 2 Zählvariablen. Eine für AnzZeichen und eine Für AnzWort. Am Anfang beide 0.
im else zweig steigt jedes mal AnzZeichen und wenn ch=' ' dann auch AnzWort. Hier evtl. Sonderfall mehrerer Leerzeichen hintereinander betrachten, z.B. durch speichern des vorherigen Zeichens.
Und dann "könnte" sich bei jedem eoln auch die Wortzahl erhöhen (wenn nicht gleich auch eof ist).

himitsu 30. Nov 2016 15:05

AW: Beginner: Textverarbeitung
 
Zitat:

Delphi-Quellcode:
       end //Kein Semikolon?
    else
      begin

Nein, wegen dem ELSE.
Zitat:

Delphi-Quellcode:
         readln(textin) //Kein Semikolon?
       end

Man könnte es weglassen, weil danach ein END folgt, aber besser immer machen, da der Befehl ja zuende ist.

Fazit: Semikolon immer, außer vor ELSE, da dort der Gesamt-Befehl (inkl. IF) noch nicht endet.


Zitat:

Delphi-Quellcode:
         writeln(textout); //Schreibt eingelesene Zeile in textout?
         readln(textin) //Liest nächste Zeile ein? Kein Semikolon?

Variable vergessen. (string)
Und wäre es nicht besser erst einzulesen und dann zu Gelesene speichern? :zwinker:

PS: Delphi-Referenz durchsuchenTStringList

Whookie 30. Nov 2016 15:08

AW: Beginner: Textverarbeitung
 
Delphi-Quellcode:
program Textverarbeitung;
{$APPTYPE CONSOLE} uses sysutils;
var textout,textin: Text;
    ch: Char;
begin
  Assignfile(textin,'test.in');
  Assignfile(textout,'test.out');
  RESET(textin);   // Datei textin öffnen
  REWRITE(textout); // Datei textout zum überschreiben öffnen
  while not(eof(textin)) do //eof True wenn Dateiende
  begin
    if eoln(textin) then //eoln True wenn Zeilenende
    begin
      writeln(textout); // Schreibt <cr><lf> in die textout Datei
      readln(textin);  // Liest <cr><lf> aus der textin Datei (und verwirft es) <- Kein Semikolon nötig (es ist aber auch nicht verboten eins zu machen!!)
    end // kein Semikolon, weil der block mit "else" weiter geht
    else
    begin
      read(textin,ch);  // Liest ein Zeichen aus der textin - Datei
      write(textout,ch); // schreibt das soeben gelesene Zeichen in die textout - Datei
      // hier kann einfach ein Zeichenzähler geführt werden.
      // platz für den Wortzähler...
    end;
  end;
  CloseFile(textout); //Schließt textout
  CloseFile(textin); //Schließt textin
  readln();
end.

Schreib stets nur eine Anweisung pro Zeile, das ist dann auch besser zu kommentieren (und später auch zu debuggen).
Das erste Semikolon "kann" weggelassen werden, weil es die letzte Anweisung vor dem "End" ist - "muss" aber nicht, ich empfehle dir es immer zu setzen.
Das zweite Semikolon ist nicht erlaubt, weil der begin/end-Block über das "else" noch nicht abgeschlossen ist.
Dateien die du öffnest solltest du auch wieder schließen, das gilt auch für textin.

Zum Zählen gibts hier ohnehin schon Hinweise und selber lösen macht bekanntlich schlauer :thumb:

Whookie 30. Nov 2016 15:16

AW: Beginner: Textverarbeitung
 
Zitat:

Zitat von himitsu (Beitrag 1355045)

Zitat:

Delphi-Quellcode:
         writeln(textout); //Schreibt eingelesene Zeile in textout?
         readln(textin) //Liest nächste Zeile ein? Kein Semikolon?

Variable vergessen. (string)
Und wäre es nicht besser erst einzulesen und dann zu Gelesene speichern? :zwinker:

Nein das passt schon so :-D
Es wird das Zeilenende erkannt und danach in die Ausgangsdatei geschrieben. Es muss natürlich dann auch noch von der Eingangsdatei entfernt werden.

jdiephaus 30. Nov 2016 16:07

AW: Beginner: Textverarbeitung
 
Delphi-Quellcode:
program Textverarbeitung;
{$APPTYPE CONSOLE} uses sysutils;
var textout,textin: Text;
    ch: Char;
    AnzZeichen: Integer;
    AnzWort: Integer;
begin
  Assignfile(textin,'test.in');
  Assignfile(textout,'test.out');
  RESET(textin);                // Datei textin öffnen
  REWRITE(textout);             // Datei textout zum überschreiben öffnen
  AnzZeichen:=0;                // Startwert AnzZeichen
  AnzWort:=0;                   // Startwert AnzWort
  while not(eof(textin)) do     // eof True wenn Dateiende
  begin
    if eoln(textin) then        // eoln True wenn Zeilenende
    begin
      writeln(textout);         // Schreibt <cr><lf> in die textout Datei
      readln(textin);           // Liest <cr><lf> aus der textin Datei (und verwirft es)
    end
    else
    begin
      read(textin,ch);          // Liest ein Zeichen aus der textin - Datei
      write(textout,ch);        // Schreibt das soeben gelesene Zeichen in die textout - Datei
       Inc(AnzZeichen,1);       // Zählt die Anzahl der Zeichen inkl. Leerzeichen
       If eoln(textin) then
          Inc(AnzWort,1);       // Zählt die Anzahl der Zeilenumbrüche
       If ch=' ' then
          Inc(AnzWort,1);       // Zählt die Anzahl der Leerzeichen
    end;
  end;
  CloseFile(textout);           //Schließt textout
  CloseFile(textin);            //Schließt textin
  writeln('Anzahl der Zeichen: ',AnzZeichen); // Gibt Anzahl der Zeichen aus
  writeln('Anzahl der Worte: ',AnzWort);      // Gibt Anzahl der Worte aus
  readln();
end.
Vielen Dank Whookie für diese ausführliche und hilfreiche Antwort. Jetzt bin ich schon etwas schlauer.
Wie muss ich es genau verstehen, dass writeln(textout) cr und lf schreibt und readln(textin) cr und lf ausliest und verwirft? Fungiert die Funktion als Indikator in welcher Zeile man sich gerade befindet?
Wie kann ich in einem If Statement zwei Faktoren prüfen lassen bevor ich z.B. AnzWort erhöhe? Meine Lösung ist ziemlich unschön.

Ghostwalker 30. Nov 2016 16:24

AW: Beginner: Textverarbeitung
 
writeln -> Write Line -> Schreibt eine ganze Zeile. Zeilenende wird automatisch angefügt.
readln -> Read Line -> Ließt eine ganze Zeile. Das Zeilenende wird automatisch verworfen.

Analog dazu gibts auch

write -> Schreibt n Zeichen in die Datei. Zeilenende muss selbst gehandhabt werden.
read -> Ließt n Zeichen aus der Datei. Zeilende muss selbst gehandhabt werden.


vgl. dazu auch die Ausführungen in der Delphi-Hilfe :)

p80286 30. Nov 2016 17:51

AW: Beginner: Textverarbeitung
 
Zitat:

Zitat von himitsu (Beitrag 1355045)

Nee, er muß noch lernen. Kannst Du Dich nicht mehr an diese Sourcen erinnern, die formal vollkommen richtig waren, die aber praktisch keiner je genutzt hat?

Gruß
K-H

Jumpy 30. Nov 2016 18:03

AW: Beginner: Textverarbeitung
 
Zitat:

Zitat von jdiephaus (Beitrag 1355053)
Wie kann ich in einem If Statement zwei Faktoren prüfen lassen bevor ich z.B. AnzWort erhöhe? Meine Lösung ist ziemlich unschön.

Mehrere Bedingungen kann man mit "and" oder "or" verknüpfen, hier "or":

Delphi-Quellcode:
If eoln(textin) or (ch=' ') then
          Inc(AnzWort,1); // Zählt die Anzahl der Zeilenumbrüche bzw. Leerzeichen

Hier kannst du wie schon erwähnt aber Probleme kriegen, bei zwei oder mehr Leerzeichen hintereinander, oder wie sieht es bei einer leeren Zeile aus, hier muss man evtl. auch noch mal überlegen was dann passiert.

Ach ja, das ",1" bei Inc könntest du auch weglassen, da die 1 der Standardparameter ist oder so, d.h. Inc(AnzWort) geht auch.

jdiephaus 30. Nov 2016 18:26

AW: Beginner: Textverarbeitung
 
Vielen Dank für die Tipps! Ah okay Jumpy das mit dem or hatte ich probiert jedoch ch=' ' nicht in Klammern gesetzt -.-. Okay stimmt darüber hatte ich noch nicht nachgedacht. Ich versuche AnzWort dementsprechend umzubauen.

Die nächste Aufgabe ist das Programm dahingehend zu erweitern, dass alle Umlaute durch ae ue oe Ae... usw vor dem schreiben in textout geändert werden.

Das habe ich jetzt so gelöst: Funktioniert! :) :)

Delphi-Quellcode:
program Textverarbeitung;
{$APPTYPE CONSOLE} uses sysutils;
var textout,textin: Text;
    ch: Char;
    AnzZeichen: Integer;
    AnzWort: Integer;
    sZeichen: String;
    sText: String;
begin
  Assignfile(textin,'test.in');
  Assignfile(textout,'test.out');
  RESET(textin);                // Datei textin öffnen
  REWRITE(textout);             // Datei textout zum überschreiben öffnen
  AnzZeichen:=0;                // Startwert AnzZeichen
  AnzWort:=0;                   // Startwert AnzWort
  while not(eof(textin)) do     // eof True wenn Dateiende
  begin
    if eoln(textin) then        // eoln True wenn Zeilenende
    begin
      writeln(textout);         // Schreibt ganze Zeile in textout. Zeilenende wird automatisch angefügt.
      readln(textin);           // Liest ganze Zeile aus textin. Zeilenende wird automatisch verworfen.
    end
    else
    begin
      read(textin,ch);          // Liest ein Zeichen aus textin und schreibt es in ch
      sZeichen:=ch;             // String sZeichen mit Wert aus ch
      Case sZeichen of          // Ändert bestimmte Zeichen vor dem Schreiben in textout
         #196:sZeichen:='Ae';   // Ä
         #214:sZeichen:='Oe';   // Ö
         #220:sZeichen:='Ue';   // Ü
         #228:sZeichen:='ae';   // ä
         #246:sZeichen:='oe';   // ö
         #252:sZeichen:='ue';   // ü
         #223:sZeichen:='ss';   // ß
        end;
       sText:=sText+sZeichen;   // Zusammenfügen aller sZeichen zu sText
      write(textout,sZeichen);  // Schreibt das soeben gelesene Zeichen aus sZeichen in textout
       Inc(AnzZeichen);         // Zählt die Anzahl der Zeichen
       If eoln(textin) or (ch=' ') then
          Inc(AnzWort);         // Zählt die Anzahl der Zeilenumbrüche und Leerzeichen
    end;
  end;
  CloseFile(textout);           // Schließt textout
  CloseFile(textin);            // Schließt textin
    writeln(sText);               // Gibt sText aus
    writeln('Anzahl der Zeichen: ',AnzZeichen); // Gibt Anzahl der Zeichen aus
    writeln('Anzahl der Worte: ',AnzWort);      // Gibt Anzahl der Worte aus
  readln();
end.

Luckie 30. Nov 2016 22:36

AW: Beginner: Textverarbeitung
 
Da es ja nur eine Übung ist, würde ich nicht alle Sonderfälle berücksichtigen, sondern erst mal von einem idealen Text ausgehen. Will man jeden Sonderfall berücksichtigen, kommt man schnell vom 100sten ins 1000ste und dann kommt man gar nicht mehr weiter. Und ich denke, das ist nicht Sinn der Übung eine perfekte Wortzählroutine zu entwickeln.

Aber du solltest dir angewöhnen nicht jede Zeile zu kommentieren. Das macht den Code nur sehr unübersichtlich. Klar als Anfänger kann man schon mal ein paar mehr Zeilen kommentieren. Zum Beispiel Inc, wenn der Befehl für einen neu ist. Aber CloseFile kommentieren? Der Funktionsname sagt doch schon, was die Funktion macht.

Jumpy 1. Dez 2016 08:20

AW: Beginner: Textverarbeitung
 
Was mir aufgefallen ist: In sText dürften nachher die Zeilenumbrüche fehlen? Als folge sind das Wort am Ende einer Zeile und das am Anfang der nächsten Zeile evtl. zusammengeschrieben? Evtl. Lösung:

Delphi-Quellcode:
if eoln(textin) then // eoln True wenn Zeilenende
  begin
  writeln(textout); // Schreibt ganze Zeile in textout. Zeilenende wird automatisch angefügt.
  readln(textin); // Liest ganze Zeile aus textin. Zeilenende wird automatisch verworfen.
  sText:=sText+CHR(13)+CHR(10); // Zeilenumbruch hinzufügen. Kann auch 10 13 sein, kann mir das nie merken.
  end
Und dann sei noch die Bemerkung erlaubt, dass der Code jetzt eine Länge ereicht hat, bei dem man evtl. überlegen sollte Teile in eine Unterfunktion auszulagern, z.B.:

Delphi-Quellcode:
function ErsetzeUmlaute(ch:Char):String;
var sZeichen:String;
begin
  Case ch of
    #196:sZeichen:='Ae'; // Ä
    #214:sZeichen:='Oe'; // Ö
    #220:sZeichen:='Ue'; // Ü
    #228:sZeichen:='ae'; // ä
    #246:sZeichen:='oe'; // ö
    #252:sZeichen:='ue'; // ü
    #223:sZeichen:='ss'; // ß
  else
    sZeichen:=ch;
  end;
  Result:=sZeichen;
end;

//Dann in der Hauptfunktion:
//...
  read(textin,ch);
  sZeichen:=ErsetzeUmlaute(ch);
  sText:=sText+sZeichen;
  write(textout,sZeichen);
//...


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:32 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