Format (Common Lisp)
   HOME

TheInfoList



OR:

Format is a function in Common Lisp that can produce formatted text using a format string similar to the
printf format string The printf format string is a control parameter used by a class of functions in the input/output libraries of C and many other programming languages. The string is written in a simple template language: characters are usually copied literal ...
. It provides more functionality than printf, allowing the user to output numbers in English, apply certain format specifiers only under certain conditions, iterate over data structures, and output in a tabular format. This functionally originates in MIT's
Lisp Machine Lisp Lisp Machine Lisp is a programming language, a dialect of the language Lisp. A direct descendant of Maclisp, it was initially developed in the mid to late 1970s as the system programming language for the Massachusetts Institute of Technology ( ...
, where it was based on
Multics Multics ("Multiplexed Information and Computing Service") is an influential early time-sharing operating system based on the concept of a single-level memory.Dennis M. Ritchie, "The Evolution of the Unix Time-sharing System", Communications of ...
ioa_.


Specification

The format function is specified by the syntax : Directives in the control string are interpolated using the format arguments, and the thus constructed character sequence is written to the destination.


Destination

The destination may either be a stream, a dynamic string, T, or the NIL constant; the latter of which presents a special case in that it creates, formats and returns a new string object, while T refers to the standard output, usually being equivalent to the console. Streams in Common Lisp comprehend, among others, string output and file streams; hence, being capable of writing to such a variety of destinations, this function unifies capabilities distributed among distinct commands in some other programming languages, such as C's printf for console output, sprintf for string formatting, and fprintf for file writing. The multitude of destination types is exemplified in the following: ;; Prints "1 + 2 = 3" to the standard output and returns ``NIL''. (format T "1 + 2 = ~d" 3) ;; Creates and returns a new string containing "1 + 2 = 3". (format NIL "1 + 2 = ~d" 3) ;; Creates and returns a new string containing "1 + 2 = 3". (with-output-to-string (output) (format output "1 + 2 = ~d" 3)) ;; Writes to the file "outputFile.txt" the string "1 + 2 = 3". (with-open-file (output "outputFile.txt" :direction :output :if-does-not-exist :create :if-exists :append) (format output "1 + 2 = ~d" 3)) ;; Appends to the dynamic string the string "1 + 2 = 3". (let ((output-string (make-array 0 :element-type 'character :adjustable T :fill-pointer 0))) (declare (type string output-string)) (format output-string "1 + 2 = ~d" 3) (the string output-string))


Control string and format arguments

The control string may contain literal characters as well as the meta character ~ (tilde), which demarcates format directives. While literals in the input are echoed verbatim, directives produce a special output, often consuming one or more format arguments.


Directives

A format directive, introduced by a ~, is followed by zero or more prefix parameters, zero or more modifiers, and the directive type. A directive definition, hence, must conform to the pattern : The directive type is always specified by a single character, case-insensitive in the case of letters. The data to be processed by a format directive, if at all necessary, is called its format argument and may be zero or more objects of any type compatible. Whether and in which quantity such data is accepted depends on the directive and potential modifiers applied unto it. The directive type ~%, for instance, abstains from the consumption of any format arguments, whereas ~d expects exactly one integer number to print, and ~@


Example

An example of a C printf call is the following: printf("Color %s, number1 %d, number2 %05d, hex %x, float %5.2f, unsigned value %u.\n", "red", 123456, 89, 255, 3.14, 250); Using Common Lisp, this is equivalent to: (format t "Color ~A, number1 ~D, number2 ~5,'0D, hex ~X, float ~5,2F, unsigned value ~D.~%" "red" 123456 89 255 3.14 250) ;; prints: Color red, number1 123456, number2 00089, hex FF, float 3.14, unsigned value 250. Another example would be to print every element of list delimited with commas, which can be done using the , and } directives:18. A Few FORMAT Recipes
from Practical Common Lisp
(let ((groceries '(eggs bread butter carrots))) (format t "~.~%" groceries) ; Prints in uppercase (format t "~:(~~).~%" groceries)) ; Capitalizes output ;; prints: EGGS, BREAD, BUTTER, CARROTS. ;; prints: Eggs, Bread, Butter, Carrots. Note that not only is the list of values iterated over directly by format, but the commas correctly are printed ''between'' items, not ''after'' them. A yet more complex example would be printing out a list using customary English phrasing: (let ((template "The lucky winners were:~# none~;_~S~;_~S_and_~S~ ___________~:;~@{~#[~;_and~~S~^,~}~.html" ;"title=";_and~.html" ;"title="none~; ~S~; ~S and ~S~ ~:;~@{~#[~; and~">none~; ~S~; ~S and ~S~ ~:;~@{~#[~; and~~S~^,~}~">;_and~.html" ;"title="none~; ~S~; ~S and ~S~ ~:;~@{~#[~; and~">none~; ~S~; ~S and ~S~ ~:;~@{~#[~; and~~S~^,~}~")) (format nil template) ;; ⇒ "The lucky winners were: none." (format nil template 'foo) ;; ⇒ "The lucky winners were: FOO." (format nil template 'foo 'bar) ;; ⇒ "The lucky winners were: FOO and BAR." (format nil template 'foo 'bar 'baz) ;; ⇒ "The lucky winners were: FOO, BAR, and BAZ." (format nil template 'foo 'bar 'baz 'quux) ;; ⇒ "The lucky winners were: FOO, BAR, BAZ, and QUUX." ) The ability to define a new directive through ~/functionName/ provides the means for customization. The next example implements a function which prints an input string either in lowercase, uppercase or reverse style, permitting a configuration of the number of repetitions, too. (defun mydirective (destination format-argument colon-modifier-supplied-p at-sign-modifier-supplied-p &optional (repetitions 1)) "This function represents a callback suitable as a directive in a ``format'' invocation, expecting a string as its FORMAT-ARGUMENT to print REPETITIONS number of times to the DESTINATION. --- The COLON-MODIFIER-SUPPLIED-P and AT-SIGN-MODIFIER-SUPPLIED-P flags expect a generalized Boolean each, being the representatives of the ``:'' and ``@'' modifiers respectively. Their influence is defined as follows: - If no modifier is set, the FORMAT-ARGUMENT is printed without further modifications. - If the colon modifier is set, but not the at-sign modifier, the FORMAT-ARGUMENT is converted into lowercase before printing. - If the at-modifier is set, but not the colon-modifier, the FORMAT-ARGUMENT is converted into uppercase before printing. - If both modifiers are set, the FORMAT-ARGUMENT is reversed before printing. --- The number of times the FORMAT-ARGUMENT string is to be printed is determined by the prefix parameter REPETITIONS, which must be a non-negative integer number and defaults to one." (declare (type (or null (eql T) stream string) destination)) (declare (type T format-argument)) (declare (type T colon-modifier-supplied-p)) (declare (type T at-sign-modifier-supplied-p)) (declare (type (integer 0 *) repetitions)) (let ((string-to-print format-argument)) (declare (type string string-to-print)) ;; Adjust the STRING-TO-PRINT based upon the modifiers. (cond ((and colon-modifier-supplied-p at-sign-modifier-supplied-p) (setf string-to-print (reverse string-to-print))) (colon-modifier-supplied-p (setf string-to-print (string-downcase string-to-print))) (at-sign-modifier-supplied-p (setf string-to-print (string-upcase string-to-print))) (T NIL)) (loop repeat repetitions do (format destination "~a" string-to-print)))) ;; Print "Hello" a single time. (format T "~/mydirective/" "Hello") ;; Print "Hello" three times. (format T "~3/mydirective/" "Hello") ;; Print a lowercase "Hello" (= "hello") three times. (format T "~3:/mydirective/" "Hello") ;; Print an uppercase "Hello" (= "HELLO") three times. (format T "~3@/mydirective/" "Hello") ;; Print a reversed "Hello" (= "olleH") three times. (format T "~3:@/mydirective/" "Hello") Whilst format is somewhat infamous for its tendency to become opaque and hard to read, it provides a remarkably concise yet powerful syntax for a specialised and common need. A Common Lisp FORMAT summary table is available.Common Lisp FORMAT summary table
/ref>


References


Books

*Common Lisp HyperSpec]
Section 22.3 Formatted Output
*Practical Common Lisp]
Chapter 18. A Few FORMAT Recipes
Common Lisp