LISP - Formatting with Format
A Practical Guide to Lisp’s format Function
Section titled “A Practical Guide to Lisp’s format Function”The format function in Common Lisp is a uniquely powerful tool for text formatting and output. It acts like a mini-language within Lisp, allowing you to produce simple or complex strings with precise control over presentation. It’s far more capable than simple string concatenation or the printf found in other languages.
Syntax Overview
Section titled “Syntax Overview”(format destination control-string &rest arguments)destination: Where the output goes. Common values aret(for standard output, the console),nil(to return the formatted text as a new string), or a stream.control-string: A string containing plain text and special format directives. Each directive starts with a tilde (~).arguments: The values to be formatted, one for each directive that requires an argument.
Commonly Used Format Directives
Section titled “Commonly Used Format Directives”Here’s a breakdown of the most essential directives, grouped by category.
1. Basic and General-Purpose Directives
Section titled “1. Basic and General-Purpose Directives”~A(Aesthetic): Prints an argument in a human-readable format. Good for most general purposes.(format nil "Hello, ~A!" "World")->"Hello, World!"~S(S-Expression): Prints an argument in a Lisp-readable format (an S-expression), with quotes for strings and symbols.(format nil "The value is ~S." "a string")->"The value is \"a string\"."~%(Newline): Inserts a newline character.~~(Tilde): Inserts a literal tilde character.
2. Number Formatting Directives
Section titled “2. Number Formatting Directives”~D(Decimal): Prints an integer in base 10.~B(Binary): Prints an integer in base 2.~X(Hexadecimal): Prints an integer in base 16 (uppercase).~F(Floating-point): Prints a float. Can take parameters for width and precision.~R(Radix): Prints an integer in any base from 2 to 36, or as English words (e.g.,(format nil "~R" 27)->"twenty-seven").
Practical Examples
Section titled “Practical Examples”Example 1: Formatting to a String
Section titled “Example 1: Formatting to a String”Using nil as the destination is perfect for building strings programmatically.
(let ((user "Alice") (items 5)) (let ((message (format nil "User ~S has ~D item(s) in their cart." user items))) (print message)))Output
Section titled “Output”"User \"Alice\" has 5 item(s) in their cart."Example 2: Padding and Alignment
Section titled “Example 2: Padding and Alignment”Directives can take prefix parameters (mincol, padchar) to control alignment and padding. The format is ~<mincol>,<padchar><directive>.
;; Print the number 5 as a binary string, padded with '0' to a minimum width of 8.(format t "~8,'0B~%" 5)
;; Print a string right-aligned in a column of 10 characters.(format t "|~10A|~%" "test")Output
Section titled “Output”00000101| test|Modern Use Cases and Best Practices
Section titled “Modern Use Cases and Best Practices”- Structured Logging:
formatis ideal for creating detailed, well-formatted log messages. You can easily include timestamps, severity levels, and structured data. - Generating Reports: Use it to generate simple text-based reports, CSV files, or other line-based data formats.
- Readability: For complex formatting, especially with conditional logic (
~[) or iteration (~{), theformatstring can become hard to read. Consider breaking complex logic into helper functions and keeping the control string relatively simple. - Security Note: When incorporating user input into a
formatstring, always pass it as an argument to a directive (like~A). Never construct thecontrol-stringitself from untrusted input, as this can lead to security vulnerabilities (a format string attack).
Further Exploration
Section titled “Further Exploration”This tutorial only scratches the surface. The Common Lisp Hyperspec entry for format is the definitive reference. Explore advanced directives like ~{...~} for iteration over lists and ~[...~] for conditional formatting to unlock its full potential.