racket/collects/scribblings/reference/format.scrbl
2012-09-27 18:29:55 -04:00

446 lines
17 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}
@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)
(eval:alts (~a @#,(racketvalfont "#e1e20")) (~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[(~e [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
"~e" v)], the default separator is @racket[" "], and the default limit
marker is @racket["..."].
@interaction[#:eval the-eval
(~e "north")
(~e 'south)
(~e #"east")
(~e #\w)
(~e (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]
[#:notation notation
(or/c 'positional 'exponential
(-> rational? (or/c 'positional 'exponential)))
'positional]
[#: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[notation]. The exactness or inexactness of @racket[x] does not
affect its formatting.
The optional arguments control number formatting:
@itemize[
@item{@racket[notation] --- determines whether the number is printed
in positional or exponential notation. If @racket[notation] is a
function, it is applied to @racket[x] to get the notation to be used.
@interaction[#:eval the-eval
(~r 12345)
(~r 12345 #:notation 'exponential)
(let ([pick-notation
(lambda (x)
(if (or (< (abs x) 0.001) (> (abs x) 1000))
'exponential
'positional))])
(for/list ([i (in-range 1 5)])
(~r (expt 17 i) #:notation pick-notation)))
]
}
@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 formatted in exponential form, @racket[precision]
applies 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 digits are 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)
(eval:alts (~r @#,(racketvalfont "#e1e10") #:min-width 6)
(~r #e1e10 #: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))
(~r 3735928559 #:base '(up 16) #:notation 'exponential)
]}
@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] of @racket['++]) and at least two
digits, separated from the significand by the ``exponent marker''
@racket[format-exponent]:
@interaction[#:eval the-eval
(~r 1234 #:notation 'exponential #: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 #:notation 'exponential)
(~r 1234 #:notation 'exponential #: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 #:notation 'exponential
#: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)