Die beiden bisherigen Kapitel über Funktionen für die Bearbeitung
von Zeichenketten haben uns bereits mit einem soliden Grundstock
an Funktionen versorgt. In diesem dritten Kapitel sollen nun noch
die Funktionen zum Aufteilen von Strings in eine Liste sowie das
Gegenteil, nämlich das Zusammenfügen mit Trennzeichen, vorgestellt
werden.
Oft haben wir es, um ein Beispiel für das Auftrennen von Zeichenketten
zu nennen, mit Datenzeilen aus einer Datei zu tun, bei der die
einzelnen Daten-Atome durch ein Trennzeichen voneinander getrennt
sind. Eine solche Datenzeile könnte beipielsweise so aussehen:
Wir brauchen also eine Funktion, die diese Zeichenkette in eine Liste
von kleineren Strings zerlegt, wobei das Trennzeichen (hier das
Semikolon) verschwindet, da es ja kein Bestandteil der eigentlichen
Daten ist. Bevor wir aber diese Funktion selbst definieren, befassen
wir uns erst wieder mit einem Vorläufer, der aber auch für sich genommen
nützlich ist:
erstmals auftritt. Weitere Vorkommen
des Zeichens werden ignoriert. Die beiden Teilstrings werden als Liste
zurückgegeben. Das gefundene Zeichen c ist in keinem der Teilstrings
mehr enthalten (es sei denn, es kommt mehr als einmal vor). Wird das
Zeichen gar nicht gefunden, ist das zweite Listenelement ein Leerstring.
Die folgende Variante (str-divset ...) sucht nicht nur nach einem
Zeichen, sondern überprüft, ob eines der Zeichen aus dem Argument cset
gefunden wird. Ansonsten ist die Arbeitsweise gleich:
(defun str-divset(str cset / i l)
(setq i 1)
(setq l(strlen str))
(while(and(<= i l)(not(str-pos cset(substr str i 1))))
(setq i(1+ i))
)
(list(substr str 1(1- i))(substr str(1+ i)))
)
Ein paar Anwendungsbeispiele, die die Wirkung der Funktionen
verdeutlichen:
(str-div "Schraube;M12;1,5;36;367.4;252.6;0.0" ";")
=> ("Schraube" "M12;1,5;36;367.4;252.6;0.0")
(str-div "Text mit\nZeilenumbruch" "\n")
=> ("Text mit" "Zeilenumbruch")
(str-divset "Text mit\nZeilenumbruch" " \n")
=> ("Text" "mit\nZeilenumbruch")
Man sieht schon: Was jetzt noch fehlt, sind die Funktionen, die
das Zerlegen weiterführen. Die beiden nachfolgenden Funktionen
bauen auf die beiden vorigen auf und arbeiten rekursiv. Ich denke,
daß man bei Zeichenketten ruhig auf Rekursion setzen kann, da in
Autolisp immer zeilenweise gelesen wird. Systemgrenzen werden hier
also sicherlich nicht erreicht.
Sollten Bedenken wegen der Rekursion bestehen, dann sollte man
das als Anreiz auffassen, über eine iterative Version nachzudenken.
In meiner fast AutoLisp-Praxis bin ich mit dieser Version von
(str-tok ...) jedenfalls nie an Grenzen gestoßen, und sie
ist in meiner Bibliothek sicherlich die am häufigsten verwendete
Funktion für die Bearbeitung von Strings.
(defun str-tok(str c / tmp)
(if(/= str "")
(progn
(setq tmp(str-div str c))
(append(list(car tmp))(str-tok(cadr tmp)c))
)
)
)
(defun str-tokset(str cset / tmp)
(if(/= str"")
(progn
(setq tmp(str-divset str cset))
(append(list(car tmp))(str-tokset(cadr tmp)cset))
)
)
)
Anwendungsbeispiele:
(str-tok "Schraube;M12;1,5;36;367.4;252.6;0.0" ";")
=> ("Schraube" "M12" "1,5" "36" "367.4" "252.6" "0.0")
(str-tokset filename "\\/.")
=> ("C:" "Programme" "AutoCAD" "Support" "acad" "lsp")
Das letzte Beispiel zeigt, wie die Trennung mittels eines Sets
von Zeichen sinnvoll eingesetzt werden kann, wenn gar nicht so
recht klar ist, welches Trennzeichen überhaupt vorliegt. In AutoLisp
kann für Dateiangaben sowohl der Backslash "\\" (der natürlich doppelt
geschrieben werden muß, da ein einzelner Backslash als Steuerzeichen
aufgefasst würde!!!) als auch der normale Schrägstrich verwendet
werden.
Wieso überhaupt der Backslash als Trennzeichen Einzug in die MS-DOS-Welt
und damit auch in Windows halten konnte, wird ausserhalb von Redmond
sowieso niemand begreifen. Im Zuge der Internetprogrammierung usw. werden
wir aber auch auf Windows-Rechnern immer damit leben müssen, dass
Pfade mal den Backslash und mal den Slash enthalten. Zum Glück ist der
Slash '/' als Zeichen in Windows-Dateinamen verboten, sonst wäre das Chaos
komplett! Da dies aber so ist, können wir mit (str-tokset ... "\\/")
beide Fälle gleichzeitig erschlagen.