In diesem und in den nächsten drei Kapiteln geht es um Regelausdrücke. Nein,
es geht definitiv nicht um irgendwelche Ausdrücke, die eine gerade von ihrer
monatlichen Regel geplagte Frau ihrem werten Gatten an den Kopf wirft.
Regelausdrücke oder Reguläre Ausdrücke sind ein mächtiges Werkzeug, mit dem
man auf einem Rechner Texte bearbeiten kann.
Kürzlich bekam ich eine Mail von einem mir bekannten AutoCAD-Anwender mit
der Bitte um Hilfe bei einem Lisp-Problem. Wie so oft haperte es auch ein Wenig
an der Formulierung des Problems. Ich fasse die Aufgabenstellung mal so
zusammen:
In einer Textdatei mit Geländedaten oder irgendetwas Vergleichbarem sind
zeilenweise Zahlen in eine Zeichenkette eingebettet, also nach dem Muster
"text text 123.45 text text". Es kann mal mehr Text vorhanden sein oder auch
weniger, aber irgendwo findet sich immer eine Zahl mit je einer Leerstelle
links und rechts daneben. Das Dezimaltrennzeichen (kann ein Punkt oder Komma
sein) reicht allein als Identifikationsmerkmal nicht aus, da Kommata und
Punkte auch noch woanders im Text auftauchen können.
Die Aufgabe besteht darin, zu den Zahlen eine Konstante zu addieren - das
bedeutet: Das ganze Gelände soll tiefergelegt werden;-) Na ja, oder auch
höher... Der Text soll natürlich unangetastet bleiben.
Ich hätte das Ganze natürlich per Mail beantworten können - aber es sollen ja
alle was davon haben, und deshalb erweitere ich meine Seiten um dieses Thema.
Dieses Problem ist stellvertretend für viele ähnliche Sachen, an denen so
mancher herumknabbert, und deswegen setze ich das mal hier herein.
Die Lösung: Das Ganze schreit förmlich nach Regulären Ausdrücken. Unter RE
(regular expressions = reguläre Ausdrücke) versteht man eine formale Syntax
von Ausdrücken, mit denen man bestimmte Stellen in einer Zeichenkette durch
etwas anderes ersetzen kann. Im Prinzip also das, was jedes
Textverarbeitungsprogramm im Menü unter "Suchen und Ersetzen" bietet. Na ja,
im Prinzip...
Natürlich kann man in MS Word den Protagonisten eines Romans, der bisher
"Müller" hieß, problemlos in "Meyer" umbenennen. Das sind die einfachen
Aufgaben. Die meisten Programme haben aber deutliche Grenzen, was das Suchen
und Ersetzen angeht. Und AutoCAD ist in dieser Hinsicht ganz arm dran: Mehr
als "Müller" durch "Meyer" ersetzen ist kaum drin. Und in Lisp gibt's nur
WCMATCH - eine reichlich armselige Funktion.
Mit den Regular Expressions ist aber praktisch alles möglich. Die RE gab es
auf UNIX-Rechnern schon seit vielen Jahren, in der Windows-Welt setzen sie
sich mittlerweile auch durch. Allerdings gibt es unzählige 'Dialekte' - eine
Version setzt allerdings einen Quasi-Standard, und das sind die RE, die in der
Programmiersprache Perl eingebaut sind. Andere Programmiersprachen wie PHP
oder Python halten sich inzwischen an diesen Standard.
Was läge also näher, als dieses Werkzeug auch in Autolisp zu nutzen? Nichts,
ausser der Tatsache, dass man das dem guten AutoLisp erstmal beibringen
muss;-) Zum Glück gibt es aber PCRE (Perl Compatible Regular Expressions),
eine freie Bibliothek (in C geschrieben), mit der man diese Funktionalität in
andere Programme einbauen kann. Ich habe schon vor gut 3 Jahren mal eine
Implementation für Autolisp geschrieben, die liegt auch seitdem bei Cadwiesel
zum Download bereit. Interessiert hat's aber niemand, das war wohl der
absolute Ladenhüter dort. Na ja, die war auch für Acad 2000, das ist ja
Schnee von gestern, und ich vermute, dass einfach keine so recht etwas damit
anfangen konnte, da eine ausführliche Dokumentation fehlte.
Wie dem auch sei, um das hier vorliegende Problem zu lösen, nämlich zu einer
in einem Text verbuddelten Zahl eine Konstante zu addieren, habe ich das Ganze
mal neu kompiliert - jetzt läuft das auch in AutoCAD 2006, 2005 und 2004. Und
siehe da: Das Problem lässt sich mal wieder mit zwei Zeilen Lisp-Code lösen
(dass da natürlich ein paar tausend Zeilen C-Code dahinterstecken, vergessen
wir einfach). So könnte das Ganze aussehen:
(if(null pcre-sr)(load"pcre.lsp"))
(defun solution-sample( / lines number result)
(setq lines
(list
"Irgendwas irgendwie irgendwo z.B. die Zahl 123.45 oder so!"
"Irgendwas irgendwie irgendwo z.B. die Zahl 678.9 oder so!"
"Irgendwas irgendwie irgendwo z.B. die Zahl 22.999999 oder so!"
)
)
(foreach line lines
(print(add-const line 0.77))
)
(princ)
)
(defun add-const(line const / number)
(setq number(pcre-sr " (\\d+\\.\\d+) " "\\1" line ""))
(pcre-sr "(.*) (\\d+\\.\\d+) (.*)" (strcat"\\1 "
(rtos(+(atof number)const)2 2)" \\3") line "")
)
Ja, ja, ein bisschen kryptisch sieht das schon aus! Aber das können wir
klären: Alles, was in der Funktion (solution-sample) steht, ist nur Testumgebung
und sollte eigentlich klar sein. In der Praxis sollte all das durch eine
Routine ersetzt werden, die die tatsächlichen Zeichenketten aus einer Datei
einliest. Es kommt einzig und allein auf die beiden Zeilen innerhals der
Funktion add-const an, und die werden wir näher untersuchen (Hier musste aber
aus Platzgründen umbrochen werden, sodass sich 3 Zeilen ergeben).
Zunächst müssen wir uns aber erst einmal ein bisschen in die Regulären
Ausdrücke einarbeiten. Das tun wir im nächsten Kapitel mit dem Titel
"Hasso, such!".