racket/collects/scribblings/reference/format.scrbl
Matthew Flatt b53e458e3f add `racket/format'
The new library is Ryan's `unstable/cat', but the names have been
changed. (The task of removing `unstable/cat' remains.)
2012-09-07 08:16:37 -06:00

406 lines
15 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/struct
scribble/eval
"mz.rkt"
(for-label racket/contract
racket/math
racket/format))
@(begin
(define the-eval (make-base-eval))
(the-eval '(require racket/math racket/format)))
@title[#:tag "format"]{Converting Values to Strings}
@author[@author+email["Ryan Culpepper" "ryanc@racket-lang.org"]]
@note-lib[racket/format]
The @racketmodname[racket/format] library provides functions for
converting Racket values to strings. In addition to features like
padding and numeric formatting, the functions have the virtue of being
shorter than @racket[format] (with format string),
@racket[number->string], or @racket[string-append].
@defproc[(~a [v any/c] ...
[#:separator separator string? ""]
[#:width width (or/c exact-nonnegative-integer? #f) #f]
[#:max-width max-width (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
[#:min-width min-width exact-nonnegative-integer? (or width 0)]
[#:limit-marker limit-marker string? ""]
[#:align align (or/c 'left 'center 'right) 'left]
[#:pad-string pad-string non-empty-string? " "]
[#:left-pad-string left-pad-string non-empty-string? pad-string]
[#:right-pad-string right-pad-string non-empty-string? pad-string])
string?]{
Converts each @racket[v] to a string in @racket[display] mode---that
is, like @racket[(format "~a" v)]---then concatentates the results
with @racket[separator] between consecutive items, and then pads or
truncates the string to be at least @racket[min-width] characters and
at most @racket[max-width] characters.
@interaction[#:eval the-eval
(~a "north")
(~a 'south)
(~a #"east")
(~a #\w "e" 'st)
(~a (list "red" 'green #"blue"))
(~a 17)
(~a #e1e20)
(~a pi)
(~a (expt 6.1 87))
]
The @racket[~a] function is primarily useful for strings, numbers, and other
atomic data. The @racket[~v] and @racket[~s] functions are better suited to
compound data.
Let @racket[_s] be the concatenated string forms of the @racket[v]s
plus separators. If @racket[_s] is longer than @racket[max-width]
characters, it is truncated to exactly @racket[max-width]
characters. If @racket[_s] is shorter than @racket[min-width]
characters, it is padded to exactly @racket[min-width]
characters. Otherwise @racket[_s] is returned unchanged. If
@racket[min-width] is greater than @racket[max-width], an exception is
raised.
If @racket[_s] is longer than @racket[max-width] characters, it is
truncated and the end of the string is replaced with
@racket[limit-marker]. If @racket[limit-marker] is longer than
@racket[max-width], an exception is raised.
@interaction[#:eval the-eval
(~a "abcde" #:max-width 5)
(~a "abcde" #:max-width 4)
(~a "abcde" #:max-width 4 #:limit-marker "*")
(~a "abcde" #:max-width 4 #:limit-marker "...")
(~a "The quick brown fox" #:max-width 15 #:limit-marker "")
(~a "The quick brown fox" #:max-width 15 #:limit-marker "...")
]
If @racket[_s] is shorter than @racket[min-width], it is padded to at
least @racket[min-width] characters. If @racket[align] is
@racket['left], then only right padding is added; if @racket[align]
is @racket['right], then only left padding is added; and if
@racket[align] is @racket['center], then roughly equal amounts of
left padding and right padding are added.
Padding is specified as a non-empty string. Left padding consists of
@racket[left-pad-string] repeated in its entirety as many times as
possible followed by a @emph{prefix} of @racket[left-pad-string] to fill
the remaining space. In contrast, right padding consists of a
@emph{suffix} of @racket[right-pad-string] followed by a number of copies
of @racket[right-pad-string] in its entirety. Thus left padding starts
with the start of @racket[left-pad-string] and right padding ends with
the end of @racket[right-pad-string].
@interaction[#:eval the-eval
(~a "apple" #:min-width 20 #:align 'left)
(~a "pear" #:min-width 20 #:align 'left #:right-pad-string " .")
(~a "plum" #:min-width 20 #:align 'right #:left-pad-string ". ")
(~a "orange" #:min-width 20 #:align 'center
#:left-pad-string "- " #:right-pad-string " -")
]
Use @racket[width] to set both @racket[max-width] and @racket[min-width]
simultaneously, ensuring that the resulting string is exactly
@racket[width] characters long:
@interaction[#:eval the-eval
(~a "terse" #:width 6)
(~a "loquacious" #:width 6)
]
}
@;{----------------------------------------}
@defproc[(~v [v any/c] ...
[#:separator separator string? " "]
[#:width width (or/c exact-nonnegative-integer? #f) #f]
[#:max-width max-width (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
[#:min-width min-width exact-nonnegative-integer? (or width 0)]
[#:limit-marker limit-marker string? "..."]
[#:align align (or/c 'left 'center 'right) 'left]
[#:pad-string pad-string non-empty-string? " "]
[#:left-pad-string left-pad-string non-empty-string? pad-string]
[#:right-pad-string right-pad-string non-empty-string? pad-string])
string?]{
Like @racket[~a], but each value is converted like @racket[(format
"~v" v)], the default separator is @racket[" "], and the default limit
marker is @racket["..."].
@interaction[#:eval the-eval
(~v "north")
(~v 'south)
(~v #"east")
(~v #\w)
(~v (list "red" 'green #"blue"))
]
Use @racket[~v] to produce text that talks about Racket values.
@interaction[#:eval the-eval
(let ([nums (for/list ([i 10]) i)])
(~a "The even numbers in " (~v nums)
" are " (~v (filter even? nums)) "."))
]}
@;{----------------------------------------}
@defproc[(~s [v any/c] ...
[#:separator separator string? " "]
[#:width width (or/c exact-nonnegative-integer? #f) #f]
[#:max-width max-width (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
[#:min-width min-width exact-nonnegative-integer? (or width 0)]
[#:limit-marker limit-marker string? "..."]
[#:align align (or/c 'left 'center 'right) 'left]
[#:pad-string pad-string non-empty-string? " "]
[#:left-pad-string left-pad-string non-empty-string? pad-string]
[#:right-pad-string right-pad-string non-empty-string? pad-string])
string?]{
Like @racket[~a], but each value is converted like @racket[(format
"~s" v)], the default separator is @racket[" "], and the default limit
marker is @racket["..."].
@interaction[#:eval the-eval
(~s "north")
(~s 'south)
(~s #"east")
(~s #\w)
(~s (list "red" 'green #"blue"))
]
}
@;{----------------------------------------}
@defproc[(~r [x rational?]
[#:sign sign
(or/c #f '+ '++ 'parens
(let ([ind (or/c string? (list/c string? string?))])
(list/c ind ind ind)))
#f]
[#:base base
(or/c (integer-in 2 36) (list/c 'up (integer-in 2 36)))
10]
[#:precision precision
(or/c exact-nonnegative-integer?
(list/c '= exact-nonnegative-integer?))
3]
[#:exponential? exponential
any/c
(let ([num (lambda (n) (if (list? n) (cadr n) n))])
(not (or (zero? x)
(< (expt (num base) (- (num precision)))
(abs x)
(expt (num base) (num precision))))))]
[#:exp-precision exp-precision
(or/c exact-nonnegative-integer?
(list/c '= exact-nonnegative-integer?))
5]
[#:format-exponent format-exponent
(or/c #f string? (-> exact-integer? string?))
#f]
[#:min-width min-width exact-positive-integer? 1]
[#:pad-string pad-string non-empty-string? " "])
string?]{
Converts the rational number @racket[x] to a string in either
positional or exponential notation, depending on
@racket[exponential?]. The exactness or inexactness of @racket[x] does
not affect its formatting.
The optional arguments control number formatting:
@itemize[
@item{@racket[precision] --- controls the number of digits after the decimal point
(or more accurately, the
@hyperlink["http://en.wikipedia.org/wiki/Radix_point"]{radix point}). When @racket[x]
is converted to exponential form, @racket[precision] applies only to the significand.
If @racket[precision] is a natural number, then up to @racket[precision] digits are
displayed, but trailing zeroes are dropped, and if all digits after the decimal
point are dropped the decimal point is also dropped. If @racket[precision] is
@racket[(list '= _digits)], then exactly @racket[_digits] digits after the
decimal point are used, and the decimal point is never dropped.
@interaction[#:eval the-eval
(~r pi)
(~r pi #:precision 4)
(~r pi #:precision 0)
(~r 1.5 #:precision 4)
(~r 1.5 #:precision '(= 4))
(~r 50 #:precision 2)
(~r 50 #:precision '(= 2))
(~r 50 #:precision '(= 0))
]}
@item{@racket[min-width] --- if @racket[x] would normally be printed
with fewer than @racket[min-width] digits (including the decimal
point but not including the sign indicator), the output is left-padded
using @racket[pad-string].
@interaction[#:eval the-eval
(~r 17)
(~r 17 #:min-width 4)
(~r -42 #:min-width 4)
(~r 1.5 #:min-width 4)
(~r 1.5 #:precision 4 #:min-width 10)
(~r 1.5 #:precision '(= 4) #:min-width 10)
(~r 1e10 #:min-width 6)
]}
@item{@racket[pad-string] --- specifies the string used to pad the
number to at least @racket[min-width] characters (not including the
sign indicator). The padding is placed between the sign and the normal
digits of @racket[x].
@interaction[#:eval the-eval
(~r 17 #:min-width 4 #:pad-string "0")
(~r -42 #:min-width 4 #:pad-string "0")
]}
@item{@racket[sign] --- controls how the sign of the number is
indicated:
@itemlist[
@item{If @racket[sign] is @racket[#f] (the default), no sign output is
generated if @racket[x] is either positive or zero, and a minus sign is
prefixed if @racket[x] is negative.
@interaction[#:eval the-eval
(for/list ([x '(17 0 -42)]) (~r x))
]}
@item{If @racket[sign] is @racket['+], no sign output is generated if
@racket[x] is zero, a plus sign is prefixed if @racket[x] is positive, and a
minus sign is prefixed if @racket[x] is negative.
@interaction[#:eval the-eval
(for/list ([x '(17 0 -42)]) (~r x #:sign '+))
]}
@item{If @racket[sign] is @racket['++], a plus sign is prefixed if @racket[x]
is zero or positive, and a minus sign is prefixed if @racket[x] is negative.
@interaction[#:eval the-eval
(for/list ([x '(17 0 -42)]) (~r x #:sign '++))
]}
@item{If @racket[sign] is @racket['parens], no sign output is generated if
@racket[x] is zero or positive, and the number is enclosed in parentheses if
@racket[x] is negative.
@interaction[#:eval the-eval
(for/list ([x '(17 0 -42)]) (~r x #:sign 'parens))
]}
@item{If @racket[sign] is @racket[(list _pos-ind _zero-ind _neg-ind)], then
@racket[_pos-ind], @racket[_zero-ind], and @racket[_neg-ind] are used to
indicate positive, zero, and negative numbers, respectively. Each indicator is
either a string to be used as a prefix or a list containing two strings: a
prefix and a suffix.
@interaction[#:eval the-eval
(let ([sign-table '(("" " up") "an even " ("" " down"))])
(for/list ([x '(17 0 -42)]) (~r x #:sign sign-table)))
]
The default behavior is equivalent to @racket['("" "" "-")]; the
@racket['parens] mode is equivalent to @racket['("" "" ("(" ")"))].
}
]}
@item{@racket[base] --- controls the base that @racket[x] is formatted in. If
@racket[base] is a number greater than @racket[10], then lower-case letters are
used. If @racket[base] is @racket[(list 'up _base*)] and @racket[_base*] is
greater than @racket[10], then upper-case letters are used.
@interaction[#:eval the-eval
(~r 100 #:base 7)
(~r 4.5 #:base 2)
(~r 3735928559 #:base 16)
(~r 3735928559 #:base '(up 16))
]}
@item{@racket[format-exponent] --- determines how the exponent is displayed.
If @racket[format-exponent] is a string, the exponent is displayed with an
explicit sign (as with a @racket[sign-mode] of @racket['++]) and at least two
digits, separated from the significand by the ``exponent marker''
@racket[format-exponent]:
@interaction[#:eval the-eval
(~r 1234 #:exponential? #t #:format-exponent "E")
]
If @racket[format-exponent] is @racket[#f], the ``exponent marker'' is
@racket["e"] if @racket[base] is @racket[10] and a string involving
@racket[base] otherwise:
@interaction[#:eval the-eval
(~r 1234 #:exponential? #t)
(~r 1234 #:exponential? #t #:base 8)
]
If @racket[format-exponent] is a procedure, it is applied to the exponent and
the resulting string is appended to the significand:
@interaction[#:eval the-eval
(~r 1234 #:exponential? #t
#:format-exponent (lambda (e) (format "E~a" e)))
]}
]
}
@; ----------------------------------------
@deftogether[(
@defproc[(~.a [v any/c] ...
[#:separator separator string? ""]
[#:width width (or/c exact-nonnegative-integer? #f) #f]
[#:max-width max-width (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
[#:min-width min-width exact-nonnegative-integer? (or width 0)]
[#:limit-marker limit-marker string? ""]
[#:align align (or/c 'left 'center 'right) 'left]
[#:pad-string pad-string non-empty-string? " "]
[#:left-pad-string left-pad-string non-empty-string? pad-string]
[#:right-pad-string right-pad-string non-empty-string? pad-string])
string?]
@defproc[(~.v [v any/c] ...
[#:separator separator string? " "]
[#:width width (or/c exact-nonnegative-integer? #f) #f]
[#:max-width max-width (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
[#:min-width min-width exact-nonnegative-integer? (or width 0)]
[#:limit-marker limit-marker string? "..."]
[#:align align (or/c 'left 'center 'right) 'left]
[#:pad-string pad-string non-empty-string? " "]
[#:left-pad-string left-pad-string non-empty-string? pad-string]
[#:right-pad-string right-pad-string non-empty-string? pad-string])
string?]
@defproc[(~.s [v any/c] ...
[#:separator separator string? " "]
[#:width width (or/c exact-nonnegative-integer? #f) #f]
[#:max-width max-width (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
[#:min-width min-width exact-nonnegative-integer? (or width 0)]
[#:limit-marker limit-marker string? "..."]
[#:align align (or/c 'left 'center 'right) 'left]
[#:pad-string pad-string non-empty-string? " "]
[#:left-pad-string left-pad-string non-empty-string? pad-string]
[#:right-pad-string right-pad-string non-empty-string? pad-string])
string?]
)]{
Like @racket[~a], @racket[~v], and @racket[~s], but each @racket[v] is
formatted like @racket[(format "~.a" v)], @racket[(format "~.v" v)],
and @racket[(format "~.s" v)], respectively.}
@; ----------------------------------------
@(close-eval the-eval)