Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Buchstaben zählen
Hennar - Do 16.09.10 19:17
Titel: Buchstaben zählen
Hallo Zusammen,
Wir sollen ein Programm schreiben, das in einem MemoText alle Buchstaben zählt und diese dann in eine vorher erstellte Tabelle einträgt. Beispiel:
MemoText: Hallo Welt
Tabelle :
Buchstabe Häufigekit
A = 1
L = 3
usw.
Für das a hb ich das wie folgt gelöst:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TForm1.BBuchstabenstatistikClick(Sender: TObject); var i, n, anzahl :integer; text:string;
begin SGTabelle.Cells[0,0]:='Buchstabe'; SGTabelle.Cells[1,0]:='Häufigkeit'; For i:=0 to 26 do begin SGTabelle.Cells[0,i+1]:=char(i+65); end; text:=memo1.Text;
For i:=1 to length(text) do begin if text[i]=char(65) then anzahl:=anzahl+1; SGTabelle.Cells[1,1]:=inttostr(anzahl); end;
end |
Nur wollte ich vermeiden 26 bzw. 52 (Groß und Kleinschreibung) If-ABfragen zu schreiben.
Nur weiß ich leider nicht wie ich das lösen könnte, da ja auch noch der Eintrag in den richtigen
Punkt der Tabelle erfolgen muss.
Schonmal vielen Dank im Voraus,
Gruß Hennar
platzwart - Do 16.09.10 19:28
Ein Array für die Häufigkeit der Buchstaben:
Delphi-Quelltext
1: 2:
| var count: array[0..25] of Integer; |
Das Zählen geht in einer Schleife:
Delphi-Quelltext
1: 2:
| For i:=1 to Length(text) do Inc(count[Ord(text[i])-65]); |
Gausi - Do 16.09.10 19:36
Mal so als Idee, damit man sich die Rechnerei spart.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var anz: Array[AnsiChar] of Integer; i: integer; s: AnsiString; c: AnsiChar;
for c := low(AnsiChar) to high(AnsiChar) do anz[c] := 0;
for i := 1 to length(s) do inc(anz[s[i]]); |
Dann musst du nur nach das Array anz im Grid anzeigen lassen. :)
Tranx - Do 16.09.10 19:37
Hallo,
schreibe doch das Ganze mit einem Array:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| procedure TForm1.BBuchstabenstatistikClick(Sender: TObject); var i, j : integer; Anzahl : Array[65..91] of longint; begin SGTabelle.Cells[0,0]:='Buchstabe'; SGTabelle.Cells[1,0]:='Häufigkeit'; For i:=0 to 26 do begin SGTabelle.Cells[0,i+1]:=char(i+65); end; for i:=65 to 91 do Anzahl[i]:=0; For i:=1 to length(Memo1.text) do begin j := Ord(UpperCase(Memo1.text[i])); if j in [65..91] then inc(Anzahl[j]); end;
for i:=65 to 91 do begin SGTabelle.Cells[1,i-64]:=IntToStr(Anzahl[i]) end;
end |
das sollte funktionieren,
Gruß
Gunther
Hennar - Do 16.09.10 20:05
Hallo Gunther und die anderen vielen Dank schonmal, haben in Informatik nur noch nie mit Arrays gearbeitet, aber ich werd mich mal einlesen.
Beim Compilieren gibt er nur leider folgende Fehlermeldung aus :
[Pascal Fehler] Unit1.pas(59): E2008 Inkompatible Typen
Das ist die Zeile :
Delphi-Quelltext
1:
| j := Ord(UpperCase(Memo1.text[i])); |
Weiß jemand warum ?
Tranx - Do 16.09.10 20:10
Mag sein, dass der Text, selbst indiziert, nicht als char interpretiert wird, schreibe dann das nach Konvertierung, wie Du es geschrieben hattest:
s := Uppercase(Memo1.Text);
und ...
j := Ord(s[i]);
Hennar - Do 16.09.10 20:25
Verzeiht mir meine Unwissenheit. Vielleicht steh ich auch gerade nur auf'm Schlauch,
aber wo muss ich die beiden Sachen genau einfügen ?
Und bei s := Uppercase(Memo1.Text);
kommt immer die Fehlermeldung:
[Pascal Fehler] Unit1.pas(59): E2003 Undefinierter Bezeichner: 's'
alzaimar - Do 16.09.10 21:53
Die Sache mit den Arrays ist zwar richtig, aber vielleicht ein wenig viel auf einmal.
Versuchen wir es hiermit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| if text[i]=char(65) then anzahl := StrToIntDef(SGTabelle.Cells[1,1],0); anzahl := anzahl + 1; SGTabelle.Cells[1,1] := inttostr(anzahl); end;
if text[i]=char(65) then anzahl := StrToIntDef(SGTabelle.Cells[1,2],0); anzahl := anzahl + 1; SGTabelle.Cells[1,2] := inttostr(anzahl); end; |
Die beiden Blöcke sind ja fast identisch. Entweder schreiben wir uns eine eigene Prozedur, die zu einem beliebigen Buchstaben im Grid eins dazuaddiert oder wir machen das direkt im Code.
Also:
Wenn der Buchstabe die Ordnungszahl 65 hat, dann ändern wir die Zelle #1
Wenn der Buchstabe die Ordnungszahl 66 hat, dann ändern wir die Zelle #2
...
Merkste wat?
Wenn der Buchstabe die Ordnungszahl N hat, dann ändern wir die Zelle #(N-64)
Nächster Versuch
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| Buchstabe := text[i]; Buchstabe := Upcase(Buchstabe); Buchstabe_Ordnungszahl := Ord(Buchstabe); Index_Im_StringGrid := Buchstabe_Ordnungszahl - 64; If Index_Im_StringGrid in [1..26] Then Begin anzahl := StrToIntDef(SGTabelle.Cells[1,Index_Im_StringGrid],0); anzahl := anzahl + 1; SGTabelle.Cells[1,Index_Im_StringGrid] := inttostr(anzahl); end; |
Hennar - Do 16.09.10 22:21
Erst einmal vielen Dank, der Support hier ist echt Super :D
@alzaimar:
Bin halt noch totaler Anfänger, aber ich hoffe ich habs dank dir verstanden :)
Müsste ich also Buchstabe als String
Buchstabe_Ordnungszahl als Integer
Buchstabe_Im_Stringgrid als Integer
deklarieren ?
Noch eine andere Frage, was bedeutedt das Upcase ?
Gruß Hennar
alzaimar - Do 16.09.10 22:29
Ist ein Buchstabe denn eine Zeichenkette (=String) oder doch nur ein einzelnes Zeichen?
Das 'Upcase' ist eine in Delphi eingebaute Funktion, die ein Zeichen in einen Großbuchstaben umwandelt.
Du hast ja vielleicht auch Kleinbuchstaben im Text. Die Abfrage, ob dieser Index 'in [1..26]' ist, prüft eigentlich, ob da ein Buchstabe oder ein Zeichen (z.B. ein Punkt, Komma, Leerzeichen usw.) steht.
Der Rest von Dir ist richtig.
Wichtig ist, das Du es verstehst.
Hennar - Do 16.09.10 22:33
Ok, das mit dem String stimmt, ein Blick auf die Uhr erklärt vielleicht einiges :roll: :lol:
Und Upcase hab ich jetzt auch verstanden, sehr nützlich. :D
Dann hab ich soweit ich das jetzt überlicken kann, alles verstanden.
Ist halt nur schwer so ein Programm zu schreiben (ist das aller erste),
wenn einem vorher nichtmal gesagt wird das es etwas wie ein array gibt, aber naja, schule halt.
Falls ich noch weitere Probleme hab werd ich mich melden.
Vielen Dank :)
Hennar
Tante Edit sagte mit gerade:
[Pascal Fehler] Unit1.pas(64): E2003 Undefinierter Bezeichner: 'Index_Im_StringGrid'
Versteh gerade nicht wo er da ein Problem hat ?
platzwart - Do 16.09.10 23:29
Undefinierter Bezeichner bedeutet immer, dass du vergessen hast, eine Variable zu deklarieren. Welche das ist, steht hinter dem Doppelpunkt der Fehlermeldung ;)
Hennar - Do 16.09.10 23:48
Achso ok,
ich dachte es gibt da noch ein unterschied zu "nicht deklariert", danke ;)
Hennar - Fr 17.09.10 07:21
Hab Index_Im_SringGrid auch nochmal deklariert.
Programm startet jetzt auch. Allerdings zählt es nur die kleinen "a"'s und nicht die großen und auch keine anderen Buchstaben.
Und wie ich gerade merke zählt es aucvh nur bis 1, egal ob in der zeile noch 4 kleine a's sind.
Desweiteren zählt es diese auch nur, wenn im Feld noch Memo1 steht.
Das ist der aktuelle Code :
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| procedure TForm1.BBuchstabenstatistikClick(Sender: TObject); var i:integer; Buchstabe:char; text:string; Buchstabe_Ordnungszahl:integer; Buchstabe_Im_StringGrid:integer; anzahl:integer; Index_Im_StringGrid:integer;
begin SGTabelle.Cells[0,0]:='Buchstabe'; SGTabelle.Cells[1,0]:='Häufigkeit'; For i:=0 to 26 do begin SGTabelle.Cells[0,i+1]:=char(i+65); end; text:=memo1.Text; Buchstabe := text[i]; Buchstabe := Upcase(Buchstabe); Buchstabe_Ordnungszahl := Ord(Buchstabe); Index_Im_StringGrid := Buchstabe_Ordnungszahl - 64; If Index_Im_StringGrid in [1..26] Then Begin anzahl := StrToIntDef(SGTabelle.Cells[1,Index_Im_StringGrid],0); anzahl := anzahl + 1; SGTabelle.Cells[1,Index_Im_StringGrid] := inttostr(anzahl); end; end; |
Tilo - Fr 17.09.10 10:22
Hallo Hennar,
guck Dir deinen Code doch mal genauer an,
Du iterierst nicht durch das Memo.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure TForm1.BBuchstabenstatistikClick(Sender: TObject); var i:integer; Buchstabe:char; text:string; Buchstabe_Ordnungszahl:integer; Buchstabe_Im_StringGrid:integer; anzahl:integer; Index_Im_StringGrid:integer;
begin SGTabelle.Cells[0,0]:='Buchstabe'; SGTabelle.Cells[1,0]:='Häufigkeit'; For i:=0 to 26 do begin SGTabelle.Cells[0,i+1]:=char(i+65); end; text:=memo1.Text; Buchstabe := text[i]; Buchstabe := Upcase(Buchstabe); Buchstabe_Ordnungszahl := Ord(Buchstabe); Index_Im_StringGrid := Buchstabe_Ordnungszahl - 64; If Index_Im_StringGrid in [1..26] Then Begin anzahl := StrToIntDef(SGTabelle.Cells[1,Index_Im_StringGrid],0); anzahl := anzahl + 1; SGTabelle.Cells[1,Index_Im_StringGrid] := inttostr(anzahl); end; end; |
Du must zwischen text:=memo1.Text und Buchstabe:=text[i] noch einen Schleifenkopf einbauen der i von 1 bis Anzahl der Zeichen im Text durchiteriert.
Der Schleifenkörper geht dann von Buchstabe:=Test[i] bis Procedure Ende.
Der Code ist aber langsam, da Du für jeden einzelne Buchstabenposition im Text die Ausgabe aktualisierst. Wenn Du nicht im Threads arbeitest sieht der Anwender das aber nicht. Der Code wird effektiver wenn Du die Verarbeitung von der Ausgabe trennst.
Der BeispielCode von Gausi zum Beispiel ermittelt nur das Vorkommen der Buchstaben. Dadurch spart er sich das ständige Umformen mit StrToIntDef und inttostr.
Wenn der Text 10 Mio Zeichen hat führst Du diese Tranformationen 10 Mio mal aus. Bei Gausi's Code muss die Umwandlung maximal 256 mal durchgeführt werden, Jenachdem für welche (und damit wieviele) Buchstaben die Information gewünscht ist. Jeder Vergleich (hier: if Index_Im_StringGrid in [1..26] Then) und jede Umformung kostet (wenn heute im Privatbereich kaum spürbar) Rechenzeit. Im Vergleich dazu ist ein inc(Array[index]) (im Allgemeinen) um einiges schneller.
Hennar - Fr 17.09.10 21:13
Zitat: |
Der Code ist aber langsam |
Ich würd ihn trotzdem erstmal versuchen, kann ihn danach ja noch verbessern.
Leider muss ich schon wieder sagen, dass ich gerade nicht weiß wie ich das mit dem
durchiterieren machen soll.
For schleife wahrscheinlich ?! Aber wie muss ich die schreiben ?
Georg08 - Fr 17.09.10 22:17
Ich hab den Thread hier grade entdeckt...
Ich hab vor ein paar Monaten mal was geschreiben. Habs in den Anhang gelegt. Es zählt die Buchstaben und schreibt sie in ein TListView...
Hennar - Fr 17.09.10 23:04
Bin ich also nicht der einzige der das macht.
Nur würd ich lieber bei meinem Code bleiben damit ich es verstehe,
aber vielen Dank, habs mir eben mal angeguckt und gewisse paraleln sind doch da ;)
Hennar - So 19.09.10 14:13
Kann mir keiner das mit der For-schleife erklären,
wie ich die wo schreiben muss ?
Tilman - So 19.09.10 15:39
Du musst das Memo durchgehen, so in etwa:
P.S. habe ausserdem eine Zeile eingefügt, die alle Zahlen im Stringgrid erstmal auf "0" setzt
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure TForm1.BBuchstabenstatistikClick(Sender: TObject); var i,n:integer; Buchstabe:char; text:string; Buchstabe_Ordnungszahl:integer; Buchstabe_Im_StringGrid:integer; anzahl:integer; Index_Im_StringGrid:integer;
begin SGTabelle.Cells[0,0]:='Buchstabe'; SGTabelle.Cells[1,0]:='Häufigkeit'; For i:=0 to 26 do begin SGTabelle.Cells[0,i+1]:=char(i+65); SGTabelle.Cells[1,i+1] := '0'; end; text:=memo1.Text; for n := 1 to length(text) do begin Buchstabe := text[n]; Buchstabe := Upcase(Buchstabe); Buchstabe_Ordnungszahl := Ord(Buchstabe); Index_Im_StringGrid := Buchstabe_Ordnungszahl - 64; If Index_Im_StringGrid in [1..26] Then Begin anzahl := StrToIntDef(SGTabelle.Cells[1,Index_Im_StringGrid],0); anzahl := anzahl + 1; SGTabelle.Cells[1,Index_Im_StringGrid] := inttostr(anzahl); end; end; end; |
P.S. am besten früh angeöhnen: hinter jedes end; schreiben, wozu es gehört, das erleichtert die Arbeit ungemein :)
Hennar - So 19.09.10 16:22
Vielen vielen Dank :D
Tranx - So 19.09.10 16:52
Beim Buchstabenzählen ist jedoch noch eines zu bedenken:
in der deutschen Sprache gibt es ja außer den 26 Buchstaben von a bis z noch die Buchstaben ß, ä, ö, ü, also, berücksichtigt man nur eine Schreibweise, 30 Buchstaben. Das Problem ist zudem noch, dass Uppercase ä nicht in Ä etc. verwandelt. Dazu wäre dann eine Prozedur wie folgt nötig:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| function Ucase(s : string) : string; var temp : string; c : char; i : integer; begin temp := s; for i := 1 to length(s) do begin c := s[i]; case c of 'a'..'z', 'ä', 'ö', 'ü' : c := char(ord(c)-32); 'ß' : ; end; s[i] := c; end; result := s; end; |
Außerdem müssten dann die Zeilen 27 - 30 eingefügt werden und die Angabe des Zeichencodes wie folgt geändert werden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function DeZeichenNr(c : char) : integer; var n : integer; begin case c of 'a'..'z' : n := ord(c)-96; 'A'..'Z' : n := ord(c)-64; 'ä', 'Ä' : n := 27; 'ö', 'Ö' : n := 28; 'ü', 'Ü' : n := 29; 'ß' : n := 30; else n := 0; end; result := n; end; |
Dann kann der gesamte deutsche Zeichensatz durchsucht werden. Bei im Zeichensatz als Buchstaben nicht vorhandenen Zeichen wird dann 0 zurückgegeben. Also bei allen Leerzeichen, Kommatas, Punkte, Semikoli, Doppelpunkten etc. und anderen Sonderzeichen sowie den Ziffern.
Vielleicht könnt Ihr das gebrauchen. Wenn nicht, egal.
Hennar - So 19.09.10 20:57
Sonderzeichen brauchen wir nicht, es ging erstmal nur um die normalen Buchstaben.
Aber vielen Dank, ich kann es natürlich als Verbesserung einfügen :D
Marc. - So 19.09.10 21:05
Tranx hat folgendes geschrieben : |
Das Problem ist zudem noch, dass Uppercase ä nicht in Ä etc. verwandelt. |
Probier's mal mit
AnsiUpperCase('ä'); :think: :idea:
Ein Auszug aus der [url=
http://docwiki.embarcadero.com/VCL/en/AnsiStrings.UpperCase]DOH[/url]: Zitat: |
UpperCase returns a copy of the string S, with the same text but with all 7-bit ASCII characters between 'a' and 'z' converted to uppercase. To convert 8-bit international characters, use AnsiUpperCase instead. |
Grüße
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!