Common Lisp hat ein Konzept namens The Printer, das alle Funktionen zum Schreiben textueller Darstellungen von Lisp-Daten umfasst. Eine solche Funktion ist format, mit der der Programmierer die Daten nach Belieben formatieren kann.
Die Möglichkeiten von format und des Lisp Printers im Allgemeinen sind ein großes Thema; hier werden die Grundlagen der Verwendung von format beschrieben.
Die Funktion format nimmt mindestens zwei Argumente: einen Stream, in den geschrieben wird, und einen Steuerstring, der definiert, was und wie geschrieben werden soll.
Streams sind ein eigenes Konzept und werden an anderer Stelle beschrieben. Aber für den Moment musst du nur wissen, dass das Schreiben in den Stream erfolgt und dass es zwei spezielle Werte für dieses Argument gibt: t und nil. t bedeutet, in die Standardausgabe zu schreiben (genauer gesagt, den Stream, an den die Variable *standard-output* gebunden ist). Und nil bedeutet, einen String zu erzeugen und ihn zurückzugeben.
Beachte, dass format immer zu nil auswertet, außer im letzteren Fall, in dem nil als Stream angegeben ist. Dies ist eine übliche Methode, um einfach String-Interpolation oder -Konstruktion durchzuführen.
(format nil "hello world") ; => "hello world"
(format t "hello world") ; => NIL (but "hello world" is printed to standard output)
Der Steuerstring kann „Format-Direktiven“ enthalten, die format Anweisungen geben, was zu schreiben ist und wie andere Parameter für format zu interpretieren sind. In gewissem Sinne ist der Steuerstring ein Programm, das format interpretiert und ausführt. Alle Direktiven beginnen mit ~ und werden von einem Zeichen gefolgt (z. B. ~A, ~D, ~&). Die Groß- oder Kleinschreibung des Zeichens spielt keine Rolle.
Die meisten Format-Direktiven interpolieren einfach ein Argument für format in die Ausgabe. Man sagt, sie „konsumieren“ das Argument. Einige Direktiven konsumieren keine Argumente oder mehr als eines. Eine Direktive erlaubt es sogar, in der Argumentliste zu springen oder Argumente zu überspringen.
Eine sehr allgemein einsetzbare Format-Direktive ist ~A. Sie gibt eine „menschenlesbare“ Version der Daten aus.
(format nil "Value = ~a" 10) ; => "10"
(format nil "hello ~a" "world") ; => "hello world"
(format nil "The list is: ~A" (list 1 2 3)) ; => "The list is: (1 2 3)"
Eine weitere nützliche Format-Direktive ist ~S. Sie gibt eine „maschinenlesbare“ Version der Daten aus. Das kann sehr nützlich sein, wenn du die erzeugte Ausgabe als Lisp-Daten interpretieren können möchtest. Für viele Dinge sieht sie genauso aus wie ~A, aber beachte, dass die Ausgabe bei Strings zum Beispiel die Anführungszeichen enthält (escaped, wenn sie in einem anderen String enthalten sind), sodass der Wert als String-Parameter wieder eingelesen werden kann.
(format nil "~s" 10) ; => "10"
(format nil "~s" "hello world") ; => "\"hello world\""
(format nil "~s" (list 1 2 3)) ; => "(1 2 3)"
Zwei weitere sehr nützliche Direktiven sind ~% und ~&. Die erste gibt ein Zeilenumbruchzeichen aus, während die letztere eine „frische Zeile“ ausgibt. Der Unterschied besteht darin, dass ~% immer einen Zeilenumbruch ausgibt, während ~& einen ausgibt, wenn sich der Cursor gerade nicht am Zeilenanfang befindet. Keine von beiden konsumiert ein Argument.
(format nil "~%new~%lines") ; => "
new
lines"
(format nil "~&new~&lines" ; => "new
lines"
Schließlich ist ~~ eine einfache Direktive, die ein literales ~ ausgibt.
Wie fast jeder mit einem Job muss auch Layla, das Lisp-Alien, manchmal Berichte schreiben, um andere zu informieren. Sie fragt dich, ob du ihr helfen kannst, die Daten für diese Berichte zu formatieren.
Als Erstes braucht Layla eine Funktion: format-quarter-value, die zwei Parameter entgegennimmt: das Kalenderquartal und den Wert, und sie für einen Bericht formatiert. Sie sollte einen String zurückgeben.
(format-quarter-value "last" 3.14) ; => "The value last quarter: 3.14"
(format-quarter-value "this" 0) ; => "The value this quarter: 0"
Layla bedankt sich für die Funktion format-quarter-value und sagt, dass sie in der nächsten Funktion, die gebraucht wird, sehr nützlich sein wird.
Der nächste Bericht soll das Quartal und den Wert aus 2 Quartalen anzeigen, gedruckt auf zwei Zeilen.
Außerdem muss die Ausgabe in den Stream geschrieben werden, der als erstes Argument übergeben wird.
Zum Beispiel erzeugt (format-two-quarters t "last" 3.14 "this" 0) die folgende Ausgabe auf der Standardausgabe:
The value last quarter: 3.14
The value this quarter: 0
Beachte die Leerzeilen davor und danach.
Layla hat vergessen, dir zu sagen, dass Lisp-Aliens Werte gern so sehen, dass sie als Lisp-Daten lesbar sind. Also braucht sie eine neue Funktion, deren Ergebnis sich als Lisp-Daten lesen lässt (wieder in den angegebenen Stream):
(format-two-quarters-for-reading nil "last" 3.14 "this" 0) ; =>
"(\"The value last quarter: 3.14\" \"The value this quarter: 0\")"
Melde dich bei Exercism an, um Common Lisp mit 27 Konzepte92 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.