TeX mit Anschluß

Adressensuche und -einbindung in TeX

Ein nicht unbekannte Situation: Man beginnt einen Brief aufzusetzen, doch von 
der Anschrift haften nur Bruchstücke im Gedächtnis.  TeX-Anwender können jetzt 
beruhigt aufatmen, schließlich ist ihr Favorit erweiterbar. Was also lag näher, 
als dem Satzsystem ein 'Datenbankfeature' zu liefern, genauer, LaTeX um eine
Funktion zu erweitern, die es möglich macht, allein durch die Angabe der Fragmente,
die von der Adresse noch bekannt sind, den Rest selbständig zusammenzusuchen.

Die erste Überlegung galt den zu verwaltenden Daten, den Adressen und dem
Format, in dem diese vorliegen sollen. Ich habe ein einfaches Format 
gewählt, somit läßt sich eine Exportsdatei aus Adimens bzw. dBase leicht einbinden.
Die Adressen, also Name, Strasse, Ort und Telefon müssen zeilenweise in einer 
ASCII-Datei vorliegen, wobei jeder Adressenblock vom folgenden durch eine Leerzeile 
getrennt wird:

Otto Normal
Beethovenstr. 13
6100 Darmstadt
01234/56789

Karl Mustermann
...

Jede Adresse muß exakt so in der Datei, wie sie später im Adressenkopf
des Briefes erscheinen soll. Daher dürfen in der Datendatei keine
Zeichen vorkommen, die nicht zu einer Adresse gehören. Genauso muß 
die Zeilenanzahl jeder Adresse konstant gehalten sein. Nicht ausgefüllte Daten
sind durch Leerzeilen zu ersetzen, wie dies bei den Exportdateien üblich ist.

Was Umlaute in den Adressen betrifft, so hängt dies ganz davon ab, wie solche
in der vorliegenden LaTeX-Version behandelt werden. Allgemein gilt
jedoch, daß man alle weiteren Sonderzeichen in bekannter LaTeX-Schreibweise
einzugeben hat.

Einbinden

Das LaTeX-Dokument muß lediglich um den Optionsstyle 'finder' und zwei 
Befehle erweitert werden, um die Möglichkeiten des finder.sty nutzen zu
können:

\documentstyle[finder]{letter}
\begin{document}

\findname[]{}

\addressfile{}

\begin{letter}{\name   \\
               \street \\ 
               \city }
...
\end{letter}
\end{document}

Man erkennt, daß durch die Angabe eines (in geschweiften Klammern) bzw. zweier 
Suchworte im Makro \findname und dem anschließenden Aufruf des \addressfile-Makros mit dem
zugehörigen Adreßdateinamen danach die Makros \name, \street und \city (und
\telephone) zur Verfügung stehen. Bei erfolgreicher Suche enthalten diese die
vollständige Adresse.

In Serie

Wenn das Makropaket eine Adresse finden kann, sollte es sich auch auf die Bearbeitung
von Serienbriefen ausdehnen lassen. Dazu muß man lediglich einen Standardbrief, 
der die Variablen \name, \street und \city enthält, an das Makro \serienbrief{...} übergeben. 
Damit entfäält bei dieser Anwendung entfällt die Angabe von Suchwörtern. Die Datendatei
wird vollständig abgearbeitet.
 
\documentstyle[finder]{letter}
\begin{document}

\serienbrief{ %
\begin{letter}{\name   \\
               \street \\ 
               \city }
...
\end{letter}  }

\addressfile{}

\end{document}

Aufspalten

Nachdem der Benutzer in seinem Brief ein bzw. zwei Worte angegeben hat, kann die Suche 
in einer Adressendatei beginnen. Dabei wird die Datei zeilenweise von dem Makrokomplex 
eingelesen und Wort für Wort nach zu findenen Daten durchsucht. Im Aufspalten der 
Zeile in einzelne, nur durch Leerzeichen getrennte Wörter liegt
das größte Problem, dessen Lösung kennzeichnet zugleich das Herzstück des finder.sty. 
Verlief die Suche nach den vorgegebenen Wörtern erfolgreich, wird die gefundene 
Adresse in Variablen verpackt und kann von dem Anwender in dessen 
LaTeX-Dokument weiterverarbeitet werden.

Der Anfangsbereich des Styles beinhaltet neben einer Meldung alle vor dem ersten Durchlauf 
des Makropaketes notwendigen Grunddefinitionen. Viele der Einstellungen müssen in den Makros 
wiederholt werden, da es auch möglich sein soll, das Makropaket mehrmals in einem LaTeX-Dokument 
aufzurufen.

Einmal odert immer?

Der finder.sty setzt sich aus drei Makros zusammen, deren
Beschreibung gemäß des Programmdurchlaufs erfolgt.

Soll nach einer Adresse gesucht werden, so müssen an \findname[...]{...} ein
oder (optional) zwei Suchwörter übergeben werden. \findname ist so 
programmiert, daß es, falls nur ein Suchwort (in geschweiften Klammern) 
angegeben wurde, dieses zweimal an \findn@me weiterliefert. Dort werden 
die Suchwörter in den Variablen \firstname und \secondname abgelegt. Beiden 
Makros lassen sich damit auch nach dem \findname-Aufruf im LaTeX-Dokument 
verwenden.

Eine Kontrolle stellt sicher, daß keine Leerzeichen übergeben wurden. Danach sind alle Flags 
so gestellt, daß die Suche zum ersten Mal oder ggf. wieder neu beginnen kann, falls dies
die zweite Adresse ist, nach der gesucht werden soll.

Will man einen Serienbrief starten, so speichert das \serienbrief-Makro den übergebenen 
Text des Serienbriefes ab und setzt die zugehörigen Flags dementsprechend.

Suche...

Der erste Schritt besthet im Aufruf von \addressfile und der Angabe der zu
durchsuchenden Datei. Aber auch dieses Makro ist nicht das eigentliche 
Ausführende, sondern es trifft nur eine Vorentscheidung. Sollen beispielsweise mehrere
Dateien durch mehrmaliges Aufrufen des \addressfile-Befehls nach einer 
Adresse durchsucht werden und ist die Suche schon in einer der ersten 
Dateien erfolgreich, so hat sich das Weitersuchen in allen nachfolgenden Dateien erübrigt. 
Das Makro bricht in diesem Fall mit einer Bildschirmmeldung ab. 

Die Suche startet mit dem \analysefile-Makro, das vom 
\addressfile-Makro aufgerufen wird. Hier wird zuerst die Datendatei geöffnet, 
danach geklärt, ob eine Suche überhaupt stattfindet oder ob ein 
Serienbrief an alle Adressen geschrieben werden soll. Nach der
Startmeldung beginnt eine Schleife. Jeder Durchlauf entspricht
dem Einlesen eines Adressenblocks. Somit existieren im vorliegenden Falle vier
nahezu gleiche Blöcke für \name, \street, \city und \telephone. Als fünftes
schließt sich eine Zeile an, die die Leerzeile zwischen den Adressenblöcken 
einliest.

Jeder der vier Blöcke hat drei Aufgaben. Die erste besteht im Einlesen
der nächsten Datenzeile und der Übergabe an das entsprechende Makro. Darauf 
findet, falls keine Leerzeile eingelesen wurde, ein Weitergabe der Zeile zum
Durchsuchen an das \lookat-Makro statt. Sollte jedoch eine Leerzeile eingelesen
worden sein, so wird das zugehörige Makro gelöscht und mit einer 
entsprechenden Bildschirmmeldung versehen. Das Löschen ist unbedingt nötig, 
da ansonsten TeX das zugehörige Makro nicht mit einer Leerzeile, sondern
mit einem \par füllt. Dies könnte beim Verwenden des Makros im 
LateX-Dokument unangenehme Folgen haben.

Bevor ich auf die Analyse der gelesenen Zeile durch das \lookat-Makro eingehe,
möchte ich die Beschreibung des Endes des \analysefile-Makros vorziehen. Die
Situation am Ende der vier Blöcke unterscheidet sich durch drei Fälle: 

Das schlechteste Ergebnis der Suche wäre ein Mißerfolg. In diesem Fall 
werden zusammen mit einer entsprechenden Bildschirmmeldung die vier 
Adreßvariablen gelöscht. Einer erneuten Suche in einer anderen Datei steht 
dennoch nichts im Wege. Es muß nur ein \addressfile-Aufruf mit
einer anderen Adressendatei folgen.

Bei einer erfolgreichen Suche wird \stillmore auf 
'false' gesetzt und damit die Suche vorzeitig abgebrochen. Das Ergebnis 
der Suche kommt auf dem Bildschirm zur Angezeige. 

Im dritten Fall, der Serienbriefanwendung, wird die gerade gelesenen Adresse
auf dem Bildschirm ausgegeben und der Text des Serienbriefes an TeX 
weitergereicht. Die darin enthaltenen Adressenvariablen haben dabei den Inhalt 
der aktuellen Adresse.

Am Ende des \analysefile-Makros wird dann entweder eine neue Schleife gestartet
oder die Adressendatei geschlossen und das Makro beendet.

... und finden

Die eigentliche Suche findet im \lookat-Makro statt. Von größter Wichtigkeit
ist hierbei, daß die eingelesenen Zeile expandiert an dieses Makro übergeben 
wird. Daß heißt, die Zeile darf nicht in einem \line-Makro verpackt, sondern muß, wie
in der Datei, explizit hinter dem \lookat-Aufruf stehen.

Nun kommt es darauf an, die Zeile Wort für Wort zu zerhacken und dabei in 
einer bestimmten Variable immer nur ein Wort der Zeile zur Verfügung zu haben. 
Dieses läßt sich dann sehr einfach mit den Suchwörtern vergleichen. Eine Suche kann nur 
erfolgreich sein bei exakter Übereinstimmung zwischen dem in der Datedatei extrahierten
und dem zu suchendem wort: Groß- und Kleinschreibung haben also durchaus Bedeutung.

Die Aufgabe des Zerhackens einer Zeile und des Vergleichens mit den
Suchwörtern übernimmt das rekursiv definierte \lookat-Makro. 
\lookat ist mit einem Leerzeichen zwischen den beiden Übergabeparametern und 
den drei Klammeraffen (@) danach so definiert, daß es ein bestimmtes Format von
den folgenden Zeichen erwartet. #1 bekommt alle dem \lookat-Makro nachfolgenden 
Buchstaben bis zum ersten Leerzeichen zugewiesen; #2 erhält den Rest der Dateizeile bis zu den 
drei Klammeraffen, die somit als Zeilenendekennung dienen.

In \lookat liegt in der \found-Variable immer ein Wort der Zeile vor.
Dieses und auch alle anderen Wörter der Zeile werden Stück für Stück mit den
Suchwörtern verglichen. Bei erfolgreicher Suche erhält jedes gefundene
Suchwort einzeln ein Flag zugeordnet. Stehen beide Suchwörter in einem Adressenblock auf 
'true' schaltet auch \foundname auf 'true'. Beim wortweisen 
Durchsuchen der Zeile enthält demnach \rest immer den Restbestandteil der 
Zeile. Dieser wird analog zur gelesenen Zeile expandiert und wieder 
an \lookat unter Beachtung des Formats übergeben. \found erhält nun
das erste Wort vom \rest-Inhalt übergeben und der \rest-Inhalt und der Inhalt von \rest 
wird um dieses Wort verringert. Man erkennt, daß \lookat-Makros ruft sich selbst aufruft.

Noch etwas zu der Sonderstellung der Leerzeichen in den Adressenblöcken:
Da immer nur wortweise Vergleich mit den Suchwörtern erfolgt,
erklärt sich von selbst, daß diese niemals ein Leerzeichen
enthalten dürfen. Ansonsten wäre die Suche 100%ig erfolglos, da \found
immer nur ein Wort enthält.

Die Rekursion des \lookat-Makros wird entweder abgebrochen, wenn beide 
Suchwörter im aktuellen Adressenblock gefunden wurden oder \rest leer ist,
daß heißt, die momentane Zeile ganz durchsucht wurde.

Erweitern

Wie ich schon erwähnt habe, wächst die anwendungsbreite des finder.sty durch Einbezug
Eportdateien. Eine derartige Verknüpfung macht hat aber eine Anpassung
der Ausgabevariablen \name, \street und so weiter notwendig. Selbstverständlich lassen sich
die vier Makros beliebig umbenennen, gleichwohl muß bei der Einfühung weiterer 
Ausgabevariablen folgendes beachtet werden.

Gesetzt den Fall, die Anrede der Person soll noch in die Adressenblöcke
aufgenommen werden. Dazu verdoppelt man zuerst den vierten, 
\telephone-Block. Danach muß \linefour beispielsweise in \linefive und demzufolge 
\linefive in \linesix umbenannt werden. Das die Numerierung dabei stimmt, ist
nicht das Wichtige, sondern, daß \line??? nur an einer Stelle im 
\analysefile-Makro eine Dateizeile übergeben bekommt. Abschließend nennt man
noch \telephone etwa in \title um und sorgt dafür, daß am Ende des Makros
sowohl die Ausgabe, als auch gegebenenfalls das Löschen des Makros \title stattfindet.

Ich bin sicher, durch finder.sty gestaltet sich das Briefschreiben unter LaTeX 
um einiges komfortabler. UNd mit etwas Phantasie steht der Einbindung in LaTeX-dokumente
aller Art keine (fast) nichts im Wege.

[Quelle: c't, magazin für computer technik, 3/92, Seite 214ff.
 Autor : Steffen Steinhäuser]