Trick 57: Sauberes
Filtern (Ohne unfreiwillige Umcodierung)
Aufgabe: Schnell mal eben eine Textdatei einlesen und wieder
rausschreiben, garantiert ohne daß ein Zeichen verändert
wird, außer bestimmten Zeichen(folgen) oder Zeilen.
Warum: Mitunter liegt eine
Textdatei vor (ASCII oder ANSI oder noch was
anderes) und man muß einzelne Zeilen hinauswerfen, herausfischen
oder in ganz bestimmter Weise verändern, alles andere soll aber
exakt so bleiben, wie es ist. Solche Vorgänge werden gern als
"Filtern" bezeichnet.
Perlentaucher und Pythonbändiger werden hier abwinken: Mach'
ich mit einem Zweizeiler, wenn nicht gar mit "grep"! Sicher,
aber es geht darum, solche Vorgänge auch bei Bedarf innerhalb
eines FLEXes nebenbei miterledigen zu können, als Teil einer
größeren Aufgabe. Zwar kann ein FLEX auch Python- oder Perl-
skripte anstoßen und deren Ergebnisse verwerten, aber das
Vorhandensein der betr. Skriptsprache kann man leider nicht
generell voraussetzen.
OK, es gibt schon den FLEX file.flx, der Textdateien zeilenweise
liest und wieder schreibt. Aber dabei verschwinden Leerzeichen
am Zeilenende. Und: Sonderzeichen außerhalb des definierten
Bereichs von OstWest-Zeichen, vor allem in der Gegend von
186-218, werden u.U. verfälscht. Das soll nicht sein!
Lösung: Die Zeilen werden
eingelesen wie sonst auch, sie werden aber
NICHT in einer #u-Variablen zwischengespeichert, sondern, und
das ist der Trick, ganz ohne solche Umschweife gleich wieder
rausgeschrieben.
Der Hinweis soll nicht fehlen:
WENN Zwischenspeicherung, dann in einer $-Variablen! Diese
unterliegen beim Einlesen und Speichern keiner Umcodierung
oder Leerzeichenbeseitigung (siehe Fußnote ganz unten).
Sagen wir, unsere Ausgangsdatei ist
"input.txt", die Ergebnisdatei soll
"output.txt" heißen.
Wir zeigen hier einen
FLEX-Abschnitt, der das Problem löst, auf die
kürzestmögliche Weise.
Diesen Abschnitt kann man sich herauskopieren
und in beliebige FLEXe modifiziert
einbauen, wo man derartige Aktionen
braucht. Es sind mehr als zwei
Zeilen, zugegeben, es sind sieben (ohne
Öffnen und Schließen),
aber kurz und unkryptisch.
------- BEGINN DES MUSTERS
--------------------------------------
...
Die Dateien öffnen
(zum Lesen bzw. Schreiben)
open input.txt
open x output.txt
^^^^^^^^^^^^^^^^^ Beginn
der Schleife
:GLOOP
naechste Zeile lesen
get iV
war keine Zeile mehr da?
Dann Ende
if cancel jump GLEND
eine gelesene Zeile steht
jetzt in der iV
***************************************************
Hier ist der Platz zum
Manipulieren der Zeile!
Ein paar Beispiele:
Hinauswerfen: wenn "xyz" drinsteht, die Zeile weglassen
if %xyz% jump GLOOP
Herausfischen: wenn "xyz" drinsteht, die Zeile übernehmen
if not %xyz% jump GLOOP
Verändern: Z.B. Text-Ersetzung 'abc' durch 'xyz':
ins _abc_xyz_
***************************************************
In iV steht jetzt ein u.U.
veränderter Inhalt
Raus damit in die Datei,
dann Zeilenvorschub dahinter:
write
write n
jump GLOOP
:GLEND
^^^^^^^^^^ Ende der
Schleife
Dateien schliessen
close
close x
...
------- ENDE DES MUSTERS
-------------------------------------
Hinweis:
Man KANN auch auf Trick 44
zurückgreifen, der das Umcodieren einer
Datei vorführt! Man nimmt
schlicht die Zeilen heraus, die sich mit
der Umcodierung befassen, bes. die
Zeile xcode xp. Fertig eingebaut
ist das in den mitgelieferten
FLEX filecode.flx.
Ferner kann man kombinieren mit
Trick 52 ("Dateien abklappern"), um
mehrere Dateien in gleicher Weise
zu filtern.
ABER ACHTUNG:
Hier ist von TEXTdateien die Rede,
die aus ZEILEN bestehen! Die
Zeilen sind durch die Codes 13 10
getrennt, der Befehl "get"
liest genau die Zeichen zwischen
zwei solchen Kombinationen,
die Steuerzeichen selbst
gehören nicht zur Zeile. Sie werden deshalb
im write-Befehl mit dem
n (für 'newline') wieder angefügt.
Dateien ohne solche Struktur sind
ein anderes Thema (Trick 58).
Fußnote zur Umcodierung
=======================
Wenn man im FLEX schreibt:
var "xyz"\ins #nnn
was passiert dann?
Dann wird der Text, der in der iV
steht, so behandelt, als hätte man
ihn gerade im Schreibfeld
eingegeben. Und was ist das Problem?
Was man im Schreibfeld eingibt, das
ist intern immer ANSI-Code.
Im FLEX kann es aber sein, wenn er
z.B. mit X-Editor erstellt
wurde oder wenn man ASCII-Daten
bearbeitet, daß der iV-Inhalt nicht
ANSI ist, sondern ASCII. Was per
Schreibfeld eingegeben wurde,
das wird per o-Tabelle der
Indexparameter in den internen Daten-
bankcode gewandelt, normalerweise
also von ANSI nach ASCII.
Deshalb wird im Normalfall unser
ASCII-"xyz" VOR der Übergabe an
die Verarbeitung noch per o-Tabelle
nach ANSI gewandelt - um dann
sofort wieder zurückverwandelt
zu werden. Na schön, dann ist es
wieder mit "xyz" identisch, alles
in Butter!? Normalerweise ja, aber
beim Vararbeiten einer Textdatei
kann diese auch Zeichen enthalten,
die es im OstWest-ASCII nicht gibt,
z.B. 202 oder 217. Diese werden
per o.apt - aus lauter Verlegenheit
- alle auf 127 abgebildet. Für
die Abbildung ANSI->ASCII
bedeutet das aber, daß sie alle auf 217
landen, welches zufällig der
letzte Wert in o.apt ist, der die 127
zugewiesen bekommt. [Könnte
man das nicht wirklich nochmal ändern?
Gute Frage, wird notiert.
Könnte nicht mit "set c2" die gesamte
Umschalterei abgeschaltet werden?
Guter Vorschlag, steht schon
auf dem Zettel für V28.]
Wenn der FLEX nun aber mit einem
ANSI-Editor (z.B. NotePad) erstellt
wurde? Dann muß man
set
c1
geben, bevor ein "insert" kommt.
Die erste der beiden Umwandlungen
(die des FLEX-Textes in ANSI)
unterbleibt dann, aber die zweite muß
natürlich sein.
Aber wenn man intern ANSI hat und
nicht ASCII? Dann braucht man eine
andere o.xpt! Wie z.B. beim
N-Format: Die o.npt ist fast leer,
nur wenige Werte müssen aus
internen Gründen umgewandelt werden.
Klingt verzwickt? Klar,
müßte alles nicht sein, wenn man nur ein
einziges Codesystem hätte,
z.B. UTF-8. So bequem ist die reale Welt
aber nun mal nicht beschaffen.