9.6. Formatted Output


9.6. Formatted Output

It is often necessary to print strings containing the printed representations of Scheme objects, especially numbers. Doing so with Scheme's standard output routines can be tedious. For example, the tree-print procedure of Section 9.4 requires a sequence of four calls to output routines to print a simple one-line message:

 (write (tree-count node) p) (write-char #\space p) (display (tree-word node) p) (newline p) 

The formatted output facility defined in this section allows these four calls to be replaced by the single call to fprintf below.

 (fprintf p "~s ~a~%" (tree-count node) (tree-word node)) 

fprintf expects a port argument, a control string, and an indefinite number of additional arguments that are inserted into the output as specified by the control string. In the example, the value of (tree-count node) is written first, in place of ~s. This is followed by a space and the displayed value of (tree-word node), in place of ~a. The ~% is replaced in the output with a newline.

The procedure printf, also defined in this section, is like fprintf except that no port argument is expected and output is sent to the current output port.

~s, ~a, and ~% are format directives; ~s causes the first unused argument after the control string to be printed to the output via write, ~a causes the first unused argument to be printed via display, and ~% simply causes a newline character to be printed. The simple implementation of fprintf below recognizes only one other format directive, ~~, which inserts a tilde into the output. For example,

 (printf "The string ~s displays as ~~.~%" "~") 

prints

 The string "~" displays as ~. --------------------------------------------------------------------------- (let ()   ;; dofmt does all of the work. It loops through the control string   ;;recognizing format directives and printing all other characters   ;;without interpretation. A tilde at the end of a control string is   ;;treated as an ordinary character. No checks are made for proper   ;;inputs. Directives may be given in either lower or upper case. (define dofmt   (lambda (p cntl args)     (let ((nmax (- (string-length cntl) 1)))       (let loop ((n 0) (a args))         (if (<= n nmax)             (let ((c (string-ref cntl n)))               (if (and (char=? c #\~) (< n nmax))                   (case (string-ref cntl (+ n 1))                     ((#\a #\A)                      (display (car a) p)                      (loop (+ n 2) (cdr a)))                     ((#\s #\S)                      (write (car a) p)                      (loop (+ n 2) (cdr a)))                     ((#\%)                      (newline p) (loop (+ n 2) a))                     ((#\~)                      (write-char #\~ p)                      (loop (+ n 2) a))                     (else                      (write-char c p)                      (loop (+ n 1) a)))                     (begin                     (write-char c p)                     (loop (+ n 1) a))))))))) ;; printf and fprintf differ only in that fprintf passes its ;;port argument to dofmt while printf passes the current output ;;port. (set! printf   (lambda (control . args)     (dofmt (current-output-port) control args))) (set! fprintf   (lambda (p control . args)     (dofmt p control args)))) 

Exercise 9.6.1.

start example

Using the optional radix argument to number->string, augment printf and fprintf with support for the following new format directives:

  1. ~b or ~B: print the next unused argument, which must be a number, in binary;

  2. ~o or ~O: print the next unused argument, which must be a number, in octal; and

  3. ~x or ~X: print the next unused argument, which must be a number, in hexadecimal.

For example:

 (printf "#x~x #o~o #b~b~%" 16 8 2) 

would print

 #x10 #o10 #b10 
end example

Exercise 9.6.2.

start example

Add an "indirect" format directive, ~@, that treats the next unused argument, which must be a string, as if it were spliced into the current format string. For example:

 (printf "--- ~@ ---" "> ~s <" '(a b c)) 

would print

 ---> (a b c) <--- 
end example

Exercise 9.6.3.

start example

Implement format, a version of fprintf that places its output into a string instead of writing to a port. Make use of object->string from Exercise 9.5.2 to support the ~s and ~a directives.

 (let ((x 3) (y 4)) (format "~s + ~s = ~s" x y (+ x y)))  "3 + 4 = 7" 
end example

Exercise 9.6.4.

start example

Modify format, fprintf, and printf to allow a field size to be specified after the tilde in the ~a and ~s format directives. For example, the directive ~10s would cause the next unused argument to be inserted into the output left- justified in a field of size 10. If the object requires more spaces than the amount specified, allow it to extend beyond the field.

 (let ((x 'abc) (y '(def)))   (format "(cons '~5s '~5s) = ~5s"     x y (cons x y)))  "(cons 'abc '(def)) = (abc def)" 

[Hint: Use format recursively.]

end example




The Scheme Programming Language
The Scheme Programming Language
ISBN: 026251298X
EAN: 2147483647
Year: 2003
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net