Von Thomas Grasel Diesmal möchte ich mich mit SET's beschäftigen. Wie das Wort SET schon sagt handelt es sich dabei um Mengen. Ein SET kann bis zu 256 verschiedene Elemente beinhalten. Seine Deklaration erfolgt mit: type typname = set of basistyp 'basistyp' darf ein skalarer Typ sein, d.h. z.B. integer,char, eine Liste von Namen oder eine Untermenge. Dafür nun eine paar Beispiele: type numset = set of 1..50 monate = (Jan,Feb,Mrz,Apr,Mai, Jun,Jul,Aug,Sep,Okt, Nov,Dez) jahr = set of monate var zahl : numset kalender: jahr Die Variable 'zahl' kann jeden belieb- igen Wert zwischen 1 und 50 annehmen. Wobei zu beachten ist das 'zahl' eine Untermenge der Integer-Zahlen ist! Die Darstellung des Bereiches mit 'x..x' erfolgt analog zu der Deklaration bei den Matrizen. Man spricht in diesem Fall von einer Untermenge. Wenn man versucht z.B. eine 90 in 'zahl' zu schreiben, so führt dies zu einer Fehlermeldung! Die Abkürzungen der Monate in der 2. Zeile stellt eine einfache Auflistung der gewünschten Elemente dar, die in der darauf folgenden Zeile als set eingebunden wird. Hierbei werden die Elemente einfach aufgelistet, d.h. sie werden ohne ' ' geschrieben! An dem folgenden Beispiel möchte ich den Gebrauch noch einmal demonstrieren. Bei einem Menu sind folgende Eingaben erlaubt: L - Laden S - Speichern E - Editieren D - Delete Fehleingaben sollen erkannt werden. In diesem Fall bietet sich geradezu die case-Anweisung zur Selektierung der Eingaben an. So entsteht folgende Struktur, bei der 'eingabe' ein char ist: ... case eingabe of 'L': begin ... end 'S': begin ... end 'E': begin ... end 'D': begin ... end ... Dieser Aufbau funktioniert so lange einwandfrei wie 'eingabe' einen der erlaubten Buchstaben beinhaltet. Gibt man jedoch etwa 'l' ein, so führt dies schon zu einer Fehlermeldung mit anschließendem Programmabbruch. Dies liegt daran das Kyan-Pascal nicht erkennt das die case-Anweisung für das 'l' keinen Abschnitt enthält. Abhilfe kann man schaffen indem man eine Sicherheitsabfrage vor die case- Scheife einfügt. ... if (eingabe='L') or (eingabe='S') or (eingabe='E') or (eingabe='D') then begin case eingabe of ... end else begin (* Fehleranzeige*) ... end ... Wie man sieht ist dies ein ganz schöner Aufwand. Als Nebeneffekt bekommt man jedoch auch die Möglichkeit für eine Fehleranzeige. Wenn man nun noch gerne die zu den obigen Großbuchstaben gehörigen Kleinbuchstaben zulassen will, geht die Übersichtlichkeit entgültig verloren. Abhilfe schafft da die Anwendung von SET's. Man legt sich einen Set an, der Zeichen (char) beinhalten kann. Im Programm füllt man den Set dann mit allen erlaubten Variablen. Wie das dann genau aussieht, sieht man an dem folgenden Teilprogramm: ... var keyset: set of char ... keyset:=+('L','l','S','s','E','e','D', 'd'+) ... if eingabe in keyset then begin case eingabe of ... end else begin (* Fehleranzeige *) end ... Wie man sieht bringt der Einsatz von Set's sehr viel Übersichtlichkeit in die Sache. Der 'in'-Befehl wurde ja schon im Pascal-Kurs #6 eingeführt. Damals wurde er benuzt um zu überprüfen ob eine Integer-Zahl innerhalb des Bereichs von 1 bis 99 lag. Auch diesmal werden Integer-Zahlen verglichen. Der Set speichert seinen Inhalt anhand des ATASCII-Codes ab. Nun muß also nur noch verglichen werden ob der ATASII-Code der Eingabe in der Menge 'keyset' enthalten ist. Man sieht der 'in'-Befehl ist recht vielfältig anwendbar. Zu beachten ist jedoch das er nur mit 8-Bit vorzeichen- losen Zahlen arbeitet. D.h. er kann nur die Zahlen von 0 bis 255 bearbeiten. So muß man bei der Verwendung von Integer- Zahlen im Zusammenhang mit dem 'in'- Befehl darauf achten das man keine negativen und Zahlen größer 255 ver- wendet. Definiert man sich aber selber Elemente zu einer Menge, d.h. benutzt man nicht schon vorgefertigte Typen wie char oder Integer's, so speichert der Rechner die Elemente als Zahl von 0 bis 255 ab. Die 0 erhält dabei das erste Element usw. Die case-Schleife arbeitet ähnlich. Auch sie arbeitet mit Zahlen die für die Zeichen stehen. So werden auch hier char's durch ihren ATASII-Code ersetzt. Daraus erklärt sich auch wieso die case-Schleife nicht mit String's zusammenarbeitet. Dieser läßt sich natürlich nicht mehr als 2-Byte Integer-Zahl darstellen. Für Abhilfe kann man mit folgendem Trick sorgen. Man definiert sich einen Set der alle nötigen Selektionselemente enthält. Somit werden die einzelnen Elemente nicht mehr durch einen String, sondern durch eine 8-Bit-Zahl symbolisiert, und mit dieser kann die case-Schleife ja wieder arbeiten! In dem Programm wird nun zuerst über- prüft ob die Eingabe überhaupt in der case-Schleife abgefragt wird, falls nicht wird sie übersprungen und zur Fehleranzeige verzweigt. Nun aber zu weiteren Anwendungsmöglich- keiten von Set's. Es gibt drei Operation die auf Set's angewendet werden können. Dies sind +,*,-. In der folgenden Tabelle sind a,b und c Set's vom gleichen!!! Typ. Die Symbole stehen für: c:=a+b Der Inhalt von a und b wird nach c kopiert. Gleiche Elemente natürlich nur einmal. Entspricht 'a vereinigt b' in der Mengen- lehre. c:=a*b Alle Elemente die in a und b vorkommen, werden nach c kopiert. Entspricht 'a ge- schnitten b'. c:=a-b Löscht alle die Elemente in a, die in a und b vorkommen. Ebenso gibt es 7 Vergleichsoperatoren für Set's die als Erbegnis jeweils 'true' oder 'false' ergeben: a=b Test ob a gleich b. D.h. gleiche Anzahl von Elementen, sowie Gleichheit der Elemente selbst, wobei ihre Reihenfolge jedoch ohne belang ist. a<>b Entspricht not(a=b). Liefert also immer genau das Gegenteil von a=b. a<=b Ergibt 'true' falls a Teilmenge von b. D.h. alle Elemente in a gibt es auch in b. a>=b Ergibt 'true' falls a alle Elemente von b enthält. Achtung in der Anleitung von Kyan-Pascal ist hier fälschlicherweise a=>b abgedruckt! k in b Test ob ob der Inhalt der Variablen k in der Menge b ent- halten ist. Dabei muß k vom gleichen Typ sein wie der Set b. Achtung: k ist kein Set, sondern nur vom gleichen Typ wie der Set! 2 Funktion für die Set's bilden den Abschluß der Auflistung: succ(a) Ermittelt den Nachfolger eines Elements. pred(a) Ermittelt den Vorgänger eines Elements. Hat man zum Beispiel den schon oben erwähnten Set var monate: (Jan,Feb,Mrz,Apr,Mai, Jun,Jul,Aug,Sep,Okt, Nov,Dez) definiert, so liefert succ('Feb') als Ergebnis 'Mrz'. Analog liefert pred('Nov') 'Okt'. Dies funktioniert auch an den zwei 'Enden' der Aufzählung so liefert pred('Jan') 'Dez', sowie succ('Dez') 'Jan'. Das Ganze funktioniert natürlich auch mit integers oder chars! So das war's. Aus Platzgründen werde ich das für diesen Monat angekündigte Utility erst im nächsten Monat veröffentlichen. Außerdem gibt's noch ein Demo zum varianten Verbund das auch Set's benutzt.