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!


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










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:
"Schraube;M12;1,5;36;367.4;252.6;0.0"
                  
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:
                  
(defun str-div(str c / i l )
  (setq i 1)
  (setq l(strlen str))
  (while(and(<= i l)(/=(substr str i 1)c))
    (setq i(1+ i))
  )
  (list(substr str 1(1- i))(substr str(1+ i)))
)
                  
(str-div ...) teilt den String str an der Stelle in zwei Teile, an dem das Zeichen c 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.

Zum Schluß soll nun noch das Gegenteil der Zerlegung vorgestellt werden: Eine Liste mit Teilstrings soll unter Einfügung eines Trenners zu einer Zeichenkette vereinigt werden:
(defun str-untok ls c / )
  (strcat
    (car ls)
    (apply 'strcat
      (mapcar '(lambda (s / )(strcat c s)))
      (cdr ls)
    )
  )
)
                  
Die Anwendungsbeispiel sind jetzt nicht ausgesprochen originell, sondern sachdienlich:
(str-untok
 '("Schraube" "M12" "1,5" "36" "367.4" "252.6" "0.0")
  ";"
)
  => "Schraube;M12;1,5;36;367.4;252.6;0.0" ";"

(str-untok
  '("C:" "Programme" "AutoCAD" "Support" "acad" "lsp")
  "/"
)
  => "C:/Programme/AutoCAD/Support/acad/lsp")
                  
_OOPS!!! - Natürlich ist da jetzt ein Fehler drin! Es kann zu den Funktionen, die mit einem Set von Zeichen arbeiten, keine Gegenteilsfunktion geben. Die Wirkungsweise von (str-untok ...) wird aber trotzdem sehr schön verdeutlicht. Wir alle kennen doch sicher den Unterschied zwischen formalen Fehlern (das sind die, die der Interpreter, Compiler usw. anmeckert) und den inhaltlichen Fehlern (das sind die, die bestenfalls der Kunde anmeckert). Ein solcher inhaltlicher Fehler liegt hier vor: natürlich muss das am Ende acad.lsp heissen!

Oder doch nicht??? Das kann doch gar nicht beurteilt werden: Jeder kann sich unter .../support/ ein Unterverzeichnis acad einrichten, und darin wiederum eines namens lsp. Ob die Variable 'filename' wirklich einen Dateinamen enthält oder ein Verzeichnis, das wissen wir doch gar nicht. Wir haben hier einfach den Fall eines möglichen inhaltlichen Fehlers, der aber unserer hier besprochenen Sache überhaupt keinen Abbruch tut.