(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 out
Auf < 50 wird dabei überprüft, weil in der IF-Abfrage nur die
Wortlänge berücksichtigt wird. In der Zeile
out = out wort
kommt 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 wort
ja 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) || out
Die 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)
END
Die 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 mit
Dazu 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
END
Diese 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 50
In 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 50
Hier fehlen 33 Leerzeichen und es gibt zwei Wortzwischenräume:
33 % 2 ergibt 16 für numPlus
33 // 2 ergibt 1 für numLeer
Die 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
END
Jetzt 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 50
Hier 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:)