[Allegro] Trick 57: Sauberes Filtern (Ohne Umcodierung)

Bernhard Eversberg ev at biblio.tu-bs.de
Mo Okt 15 08:30:37 CEST 2007


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.
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.





Mehr Informationen über die Mailingliste Allegro