(C) 1999 by Sven Drieling
ARexx verfügt über eine Vielzahl von Befehlen zur Verarbeitung von Zeichenketten. So reichen ein paar Zeilen, um einen ASCII-Text links-, rechtsbündig, zentriert oder als Blocksatz zu formatieren.
Als Beispiel zur Formatierung dient folgendes Zitat von Rainer Gellrich aus AmigaGadget #32:
"Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98
Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm
erschossen?"
"Hmmm.... Gute Frage. Seine Frau ist vors Auto gelaufen, seine zehn
Kinder wurden in den letzten vier Wochen alle von zwanzig unabhängigen
Psychopathen vergewaltigt und in 90 Wäldern der USA verstreut, seine
Firma hat seine Schweizer Nummernkonten gepfändet und den Ferkeln
Jehovas gespendet, in seinem Haus spukt der Geist von Roy Black, seine
Corvette wird von allen Tauben westlich von Timbuktu vollgeschissen und
seine Schwester trägt seit gestern Latzhosen.
Wenn Sie mich fragen, ich hab echt keine Ahnung...."
Zunächst soll nur der erste Satz linksbündig mit 50 Zeichen pro Zeile
formatiert werden. Um sich die Aufgabe möglichst einfach zu machen, wird
der Satz zunächst in eine einzige lange Zeichenkette gelegt
line = '"Was denken sie, warum hat sich dieser Mann mit einer Kaliber ' || 'Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm ' || ....und in die einzelnen Wörter zerlegt. Hierfür bieten sich folgende Befehle an:
Anzahl = WORDS(String) - Anzahl der Wörter des Strings String2 = WORD(String, n) - Liefert das n-te WortAn Trennzeichen, zwischen den Wörtern, benutzt ARexx das Leerzeichen und den Tabulator.
Zur Zerlegung der Zeile in die einzelnen Wörter reichen somit folgende
drei Zeilen
DO n = 1 TO WORDS(line) SAY WORD(line, n) END 4.DH1:PRG/rexx> rx agSplitText.rexx "Was denken sie, warum hat sich dieser Mann mit ...Als nächstes sollen die einzelnen Wörter wieder zu Zeilen mit maximal 50 Zeichen zusammengsetzt und ausgegeben werden. Dazu wird die Zeichenkette "out" erstellt. An ihr wird jeweils das nächste Wort angehängt, solange die Zeichenkette dadurch nicht die Länge von 50 Zeichen überschreitet.
out = "" DO n = 1 TO WORDS(line) wort = WORD(line, n) IF LENGTH(out) + LENGTH(wort) < 50 THEN DO out = out wort END ELSE DO SAY out out = wort END END SAY outAuf < 50 wird dabei überprüft, weil in der IF-Abfrage nur die Wortlänge berücksichtigt wird. In der Zeile
out = out wortkommt aber zusätzlich mit dem Leerzeichen ein weiteres Zeichen hinzu, das das neue Wort vom bisherigen Text trennt.
Da innerhalb der Schleife eine Zeile nur bei einen Überlauf ausgegeben wird, wird nach Ablauf der Schleife mit "SAY out" die letzte noch verbliebene Zeile ausgegeben, die zwangsläufig immer < 50 ist.
Wenn man sich die Ausgabe anschaut, kann man einen Schönheitsfehler
entdecken.
4.DH1:PRG/rexx/ag> rx agLeftText.rexx -> "Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98 Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm erschossen?"Am Anfang wurde ein zusätzliches Leerzeichen eingefügt. Das liegt daran, dass "out" zu Anfang auf "" gesetzt wird und die Zeile
out = out wortja immer ein Leerzeichen einfügt. Während dies bei allen nachfolgenden Wörtern genau das ist, was gebraucht wird, ist dies beim ersten Wort unschön. Verhindern kann man es leicht durch eine bessere Initialisierung der Schleife. "out" wird dazu am Anfang auf das erste Wort gesetzt und die Schleife beginnt daher mit dem 2. Wort.
out = WORD(line, 1) /* out aufs erste Wort setzen */ DO n = 2 TO WORDS(line) /* Schleife mit 2. Wort beginnen */ wort = WORD(line, n) ....Außerdem kann "out" am Ende der Schleife ein Leerstring sein, weshalb dieser Fall mittels IF-Abfrage abgefangen wird, um die Ausgabe zusätzlicher Leerzeilen zu vermeiden. Der Rest des Programms bleibt unverändert und schon stimmt die Ausgabe:
4.DH1:PRG/rexx/ag> rx agLeftText_2.rexx "Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98 Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm erschossen?"Da ARexx die Schleife bei "DO n = 2 TO 1 oder DO n = 2 TO 0" nicht ausführt und WORD("", 1) einen Leerstring liefert, funktioniert das Ganze auch problemlos bei nur einem oder keinem Wort in einer Zeile.
Bei der rechtsbündigen Ausgabe müssen am Anfang der Zeile soviele
Leerzeichen eingefügt werden, daß der letzte Buchstabe an Position
50 landet.
numLeer = 50 - LENGTH(out) SAY COPIES(" ", numLeer) || outDie ARexx-Funktion COPIES() erzeugt eine Zeichenketten mit der Anzahl der gewünschten Zeichen und "||" sorgt dafür, daß ARexx nicht - wie sonst üblich - selbst noch ein zusätzliches Leerzeichen einfügt.
4.DH1:PRG/rexx/ag> rx agRightText.rexx "Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98 Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm erschossen?"Zentrieren ist noch einfacher, da ARexx hierfür die Funktion CENTER() bietet:
String2 = CENTER(String, Länge, [Füllzeichen])Damit braucht im Programm nur
SAY CENTER(out, 50)zu stehen. Das optionale Füllzeichen kann dazu benutzt werden, um den Text mit anderen Zeichen als den Leerzeichen zu umschließen. Einfach mal selbst ausprobieren.
4.DH1:PRG/rexx/ag> rx agCenterText.rexx "Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98 Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm erschossen?"Problem ist dabei, dass die Programmschleife auch Zeilen erzeugen kann, die länger als 50 Zeichen sind. Dies passiert, wenn ein einzelnes Wort diese Länge überschreitet.
In diesem Fall wird "numLeer" negativ, was zum Abbruch das Programms führt und CENTER() schneidet soviel von der Zeile weg, bis sie nur noch 50 Zeichen enthält.
Als einfache Lösung erkennen die folgenden Programme diesen Fall und geben
eine erklärende Fehlermeldung aus:
IF LENGTH(line) > 50 THEN DO SAY "FEHLER!: Die erzeugte Zeile ist länger als 50 Zeichen. " SAY "Sie könnten die Breite des Textes erhöhen oder " SAY "das überlange Wort kürzen bzw. " SAY "durch Trennungen aufteilen: " out EXIT(10) ENDDie bisherigen Funktionen sind in agFormatText_1.rexx zusammengefaßt.
[ Die Beispielskripten sind in der Online-Version nicht enthalten. (an) ]
0 50 | | "Was denken sie, warum hat sich dieser Mann mit "Was denken sie, warum hat sich dieser Mann mitDazu wird wie bei der rechtsbündigen Formatierung die Anzahl der zum Auffüllen benötigten Leerzeichen berechnet. Dann wird die Zeile wieder Wort für Wort zerlegt und solange ein zusätzliches Leerzeichen eingefügt bis der Leerzeichenzähler 0 erreicht. Das alles aber nur, wenn die Zeile mehr als ein Wort enthält.
IF WORDS(line) > 1 THEN DO block = WORD(line, 1) /* block aufs erste Wort setzen */ numLeer = 50 - LENGTH(line) /* Anzahl der einzufügenden Leerzeichen */ DO n = 2 TO WORDS(line) /* Schleife mit 2. Wort beginnen */ wort = WORD(line, n) IF numLeer > 0 THEN DO block = block || " " wort /* zusätzliches Leerzeichen */ numLeer = numLeer - 1 END ELSE DO block = block wort END END SAY block END ELSE DO SAY line ENDDiese Erweiterung ist in agFormatText_2.rexx zu finden.
4.DH1:PRG/rexx/ag> rx agFormatText_2.rexx BLOCK 1. "Was denken sie, warum hat sich dieser Mann mit 2. einer Kaliber .98 3. Plastiksplittersprengmonsterkanone mit coolem 4. Granatwerfertm erschossen?" ^ ^ 0 50In diesem Fall kann das Ergebnis aber noch nicht überzeugen. Die Zeilen sind so unglücklich lang, dass teilweise mehr als ein zusätzliches Leerzeichen zwischen den einzelnen Wörtern eingefügt werden muß. Diese Anzahl wird nun in die "plus"-Zeichenkette gelegt. WORDS(line) - 1 ist dabei die Anzahl der Wortzwischenräume. Bei zwei Wörtern ist dies einer, bei drei Wörter sind dies zwei, bei vier gibt es drei Zwischenräume usw.
1. spaces = 50 - LENGTH(line) 2. numPlus = spaces % (WORDS(line) - 1) 3. numLeer = spaces // (WORDS(line) - 1) 4. plus = COPIES(" ", numPlus)In der ersten Zeile werden die benötigten Leerzeichen berechnet.
In den beiden folgenden Zeichen wird jeweils eine Ganzzahldivision durchgeführt und 'numPlus' das Ergebnis vor dem Komma und 'numLeer' der ganzzahlige Rest zugewiesen.
Beipiel:
einer Kaliber .98 ^ ^ 0 50Hier fehlen 33 Leerzeichen und es gibt zwei Wortzwischenräume:
33 % 2 ergibt 16 für numPlus 33 // 2 ergibt 1 für numLeerDie Erzeugung von "block" wird entsprechend erweitert:
IF numLeer > 0 THEN DO block = block || plus || " " wort numLeer = numLeer - 1 END ELSE DO block = block || plus wort ENDJetzt werden mindestens 16 Leerzeichen zwischen den Wörtern eingesetzt und zwischen dem 1. und 2. Wort kommt ein zusätzliches Leerzeichen hinzu.
4.DH1:PRG/rexx/ag> rx agFormatText_3.rexx BLOCK "Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98 Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm erschossen?" ^ ^ 0 50Hier sind, Dank des "Plastiksplittersprengmonsterkanone"-Wortungetüms, die Zwischenräume zwar sehr groß, aber der Text schließt bündig mit den Rändern ab.
Die großen Lücken, insbesonders bei kleinen Textbreiten, kann man nur mit einer automatischen Trennung vermeiden. Aber das ist ein anderes Thema.
In einem abschließendesm Programm ist nochmal alles zusammengefaßt. Dieses
liest einen ASCII-Text ein und gibt die einzelnen Blöcke formatiert aus.
Getrennt werden diese Blöcke innerhalb des Textes mit einer Leerzeile.
Siehe "agFormatText_4.rexx" und "zitat.txt". Als zusätzliche Parameter
kommt der Dateiname und die nun einstellbare Textbreite hinzu.
4.DH1:PRG/rexx/ag> rx agFormatText_4.rexx BLOCK 70 zitat.txt "Was denken sie, warum hat sich dieser Mann mit einer Kaliber .98 Plastiksplittersprengmonsterkanone mit coolem Granatwerfertm erschossen?"Zumindest einen Fehler besitzt das Programm aber. Bei ARexx ist derzeit die Länge einer Zeichenkette auf 65 535 Zeichen beschränkt. Wenn ein Block diese Länge überschreitet, dann bricht ARexx mit einer Fehlermeldung ab. Da Absätze mit 65 535 Zeichen aber relativ selten sind verzichte ich an dieser Stelle auf eine entsprechende Korrektur."Hmmm.... Gute Frage. Seine Frau ist vors Auto gelaufen, seine zehn Kinder wurden in den letzten vier Wochen alle von zwanzig unabhängigen Psychopathen vergewaltigt und in 90 Wäldern der USA verstreut, seine Firma hat seine Schweizer Nummernkonten gepfändet und den Ferkeln Jehovas gespendet, in seinem Haus spukt der Geist von Roy Black, seine Corvette wird von allen Tauben westlich von Timbuktu vollgeschissen und seine Schwester trägt seit gestern Latzhosen.
Wenn Sie mich fragen, ich hab echt keine Ahnung...."
tschuess
[|8:)