Ein paar Worte vorabHome   Letzte MeldungenNews   Index der Kapitel und der besprochenen FunktionenIndex   Wer ich bin, warum ich diese Seiten mache, KontaktImpressum   Ich freue mich über jeden Eintrag im Gästebuch!Gästebuch   Einige Links zu anderen AutoLisp-SeitenLinks   Copyrights und DisclaimerRechts
Hier können die kompletten Seiten als ZIP-File heruntergeladen werden!

Funktionen für komfortables Arbeiten mit Zeichenketten String-Tango
Noch mehr Funktionen für komfortableres Arbeiten mit Zeichenketten Kettenhunde
strtok zerlegt Zeichenketten anhand eines Trennzeichens Tock-Tock
Arbeiten mit Datum und Zeit in AutoLisp Zeitlos...
Dotted pairs - wie man den Programmabbruch verhindert Gepunktet?
Neue Funktionen für die Listenbearbeitung Strukturtapete
Weitere neue Funktionen für die Listenbearbeitung Listen to me!
Lambda expressions - dasSalz in der Suppe Lambada
Lambda expressions anhand eines Praxisbeispiels Unter der Erde
Where und whereever erleichtern den Umgang mit Listen Quo vadis?
Rekursion - Funktionen, die sich selbst aufrufen Katzenschwanz
Ein äusserst wichtiger Prototyp für Funktionen Nix passiert
Wo das lineare mapcar am Ende ist Tiefer rein!
Über Effekte und Neben(Seiten-)Effekte von Funktionen Seitensprünge
Die Namensräume (Sichtbarkeit) von Variablen Raumwunder
Let dient zur Schaffung kleinerer Namensräume Lass mal...
Sukzessive Verarbeitung von Listenresten mit mapcdr Der Bruder
Was in AutoLisp einfach nicht machbar ist (Teil I) Beschränkt
Was in AutoLisp einfach nicht machbar ist (Teil II) Limited Edition
Nicht mit Effekten arbeiten, sondern direkter Daten-Änderung Destruktiv
Sequenzielles vs. paralleles Abarbeiten von Argumenten Parallelwelten
Über den Umgang mit Funktionsschablonen Erwachet!
Ein Praxiskapitel über Auswahlsätze, Attribute, wcmatch und mehr Durch die Brust
Die Farben des AutoCAD Color Index und ihre RGB-Werte Alles so schön
Hier laufen die Fäden zusammen: Viele Konzepte vereint Lapsus Lispuli
Ein Spiel als Beispiel für lernfähige Funktionen Zug um Zug
Errorhandling in AutoLisp - Teil 1 Alles valsch!
Errorhandling in AutoLisp - Teil 2 Und foll Feler!
Regular expressions in AutoLisp - Teil 1 Menstruation?
Regular expressions in AutoLisp - Teil 2 Hasso, such!
Regular expressions in AutoLisp - Teil 3 Ersatzteile
Regular expressions in AutoLisp - Teil 4 Perlentaucher


Zum Einsteiger-Tutorial

Zu den ActiveX-Seiten

Meine Private HP mit Fotos, Gedichten, Musik und Postkartenversand

Mein Online-Lexikon der Fotografie

Mein völlig abgedrehtes Reisebüro

Meine bonbonfarbene Gedichteseite










Die im vorigen Kapitel besprochene Funktion (pcre-match) dient ausschließlich zum Suchen. Wollen wir Teile einer Zeichenkette ersetzen, beötigen wir eine weitere Funktion namens (pcre-sr), die allerdings im Gegensatz zur match-Funktion nicht in C geschrieben ist, sondern kurz und bündig in Lisp. Natürlich müssen Sie die Funktion erst einmal haben, Sie können sie hier herunterladen: pcre.lsp(1 kb). (pcre-sr) ist übrigens die einzige Funktion in dieser Datei, und mehr benötigen Sie dann auch nicht mehr. Laden Sie die Lisp-Datei (mit APPLOAD oder (load"pcre.lsp")) zusätzlich zur ARX-Datei pcre2006.arx.

(pcre-sr ...) muss immer mit genau vier Argumenten aufgerufen werden:
  1. das Suchmuster
  2. das Ersetzungsmuster
  3. die Zeichenkette, in der gesucht bzw. ersetzt werden soll
  4. mögliche Optionen - das Argument ist aber nicht optional!
AutoLisp erlaubt keine optionalen Funktionsargumente. Anders als bei (pcre-match) können wir also das letzte Argument nicht weglassen! Da wir aer im Rahmen dieser Übungen keine Optionen brauchen, verwenden wir als 4. Argument immer einen Leerstring.

Das Ersetzungsmuster unterscheidet sich deutlich vom Suchmuster: hier gelten ganz andere Regeln. Ein Punkt ist z.B. im Ersetzungsmuster immer ein Punkt und nicht ein Stellvertreter für ein beliebiges Zeichen. Das wichtigste ist aber eine neue Gruppe von Stellvertretern, die "\0", "\1" usw. bis "\9" heissen. Diese Stellvertreter (die in Lisp natürlich wieder mit doppeltem Backslash geschrieben werden müssen) stehen für die Unterlisten im Ergebnis von (pcre-match), das von (pcre-sr) aufgerufen wird. Ich möchte das an einem Beispiel verdeutlichen:
(pcre-sr
  "(.*)(Äpfel)(.*)(Birnen)(.*)"
  "\\1\\4\\3\\2\\5"
  "Diese Äpfel schmecken besser als jene Birnen und Kirschen"
  ""
)
=> "Diese Birnen schmecken besser als jene Äpfel und Kirschen"
                  
Wir müssen uns also gar nicht mit den einzelnen Positionen und Längen des Suchergebnisses befassen. Hier wurden die Teilzeichenketten einfach in einer neuen Reihenfolge angeordnet. Natürlich kann das Ersetzungsmuster auch Literale enthalten:
(pcre-sr
  "(.*)(Äpfel)(.*)(Birnen)(.*)"
  "\\1frischen \\4\\3verschrumpelten \\2"
  "Diese Äpfel schmecken besser als jene Birnen"
  ""
)
=> "Diese frischen Birnen schmecken besser als jene
                                  verschrumpelten Äpfel"
                  
Damit haben wir nun alle Techniken zusammen, die wir für die Lösung der gestellten Aufgabe (Hinzuaddieren einer Konstante zu Zahlen, die in Texte eingebettet sind) benötigen. Zur Vorgehensweise aber noch ein paar Erläuterungen: Zuerst müssen wir die Zahl aus dem Text extrahieren. Um die Konstante zu addieren, muss sie zwischenzeitlich in den Lisp-Datentyp Real umgewandelt werden. Nach der Addition wird sie wieder als String dargestellt und kann mit (pcre-sr) die alte Zahl in der Zeichenkette ersetzen. Diese Aufgabe lässt sich locker mit zwei Lisp-Zeilen erledigen, die in der Funktion (add-const) zu finden sind - alles andere im nun folgenden Code, nämlich die ganze Funktion (solution-sample), dient nur dazu, um Testdaten bereitzustellen und diese in einer Schleife zu durchlaufen.
(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 "")
)
                  
Die Testfunktion nimmt allerdings wenig Rücksicht auf die vorher tatsächlich vorhandene Anzahl von Nachkommastellen. Im Beispiel sind mal zwei, mal eine und mal sechs. Nach dem Ersetzen haben aber alle Zahlen genau zwei Nachkommastellen, bedingt durch den (rtos)-Parameter. In der Regel wird jedoch eine Datei mit Geländedaten sowieso eine feste Anzahl von Nachkommastellen verwenden, sodass das Problem gar nicht zum Tragen kommt. Sollte das anders sein, muss man eben doch ein wenig mehr Lisp-Code schreiben: Man stellt einfach die Anzahl der Nachkommastellen in der Original-Zeichenkette fest und übergibt diese Zahl als Parameter an (rtos). Das sollte nicht allzu schwierig sein.

Ein letzter Hinweis noch: In der ersten der beiden relevanten Zeilen könnte man natürlich auch (pcre-match) verwenden. Dann müsste man allerdings die Zahl anschließend mit (substr) aus der Zeichenkette auslesen. Die Anwendung von (pcre-sr) erspart und diese Einzelheiten. Letztlich führen aber viele Wege nach Rom, und es sind jede Menge Möglichkeiten vorstellbar, wie diese Zeilen aussehen könnten.

Noch ein ganz kurzes Wort den Dingen, die ich übergangen habe. Da sind z.B. die vier möglichen Options-Flags zu nennen:
  • i (wie 'insensitive') bedeutet, dass auf Groß- bzw. Kleinschreibung keine Rücksicht genommen wird.
  • s (wie 'single line') Ein Text mit Zeilenumbrüchen soll wie eine einzige Zeile behandelt werden
  • m (wie 'multiple lines') Ein Text mit Zeilenumbrüchen soll als Mehrzeilentext behandelt werden
  • x (wie 'eXtended pattern') sorgt dafür, dass Whitespace im Suchmuster ignoriert wird. Dadurch kann man das Suchmuster z.B. in mehrere Zeilen zerlegen, um die Lesbarkeit zu erhöhen
Für den Anfänger wird allerdings zunächst nur das Flag i von Bedeutung sein. Ein Beispiel dazu:
(pcre-match "M" "Donaudampfschifffahrtsgesellschaft" "i") => ((7 1))
                  
Auch auf Literale wurde kaum eingegangen. So ist z.B. der Punkt der Stellvertreter für ein beliebiges Zeichen. Will man aber wirklich nach einem Punkt suchen, so muss man diesem einen Backslash voranstellen, damit er als Literal gewertet wird. Und natürlich muss man den Backslash doppelt schreiben!

Im nächsten Kapitel werde ich noch auf die PCRE-Bibliothek eingehen. Dort finden sich auch Hinweise, wo man mehr über die Anwendung von regular expressions erfährt.