17
Formatted I/O The read and print statements are very limited they default to using the standard input and output devices if we want to redirect I/O, we have to specify the proper input or output stream if we want to generate formatted output, we have to use the format command So we take a look at streams and format here format is very similar to C’s printf statement • (format stream string vars) Stream is the stream that you want to redirect the output to • use T to send it to standard output, use nil if you instead want format to return the formatted output as a string to be stored Format returns nil unless you specify nil as the stream in which case format returns the string – confused? • string and vars are covered next

Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Embed Size (px)

Citation preview

Page 1: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Formatted I/O• The read and print statements are very limited

– they default to using the standard input and output devices– if we want to redirect I/O, we have to specify the proper

input or output stream– if we want to generate formatted output, we have to use the

format command

• So we take a look at streams and format here– format is very similar to C’s printf statement

• (format stream string vars)

– Stream is the stream that you want to redirect the output to • use T to send it to standard output, use nil if you instead want

format to return the formatted output as a string to be stored

– Format returns nil unless you specify nil as the stream in which case format returns the string – confused?

• string and vars are covered next

Page 2: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Specification String• The string supplied to format specifies any literal output

that you want as well as the format to be applied to any variables– the variables are optional, but you need to have one variable

for every variable specifier in the specification string• Here is a simple example where ~D is the specification

for an integer (decimal) value:– (format t “the value of x is ~D and the value of y is ~D” x y)

• if x = 5 and y = 10, this will output – the value of x is 5 and the value of y is 10

• if you only supplied variable x, you would get an error• if you supplied more than 2 variables, the excess would be ignored

– All specifications will start with ~ and be followed by one or more items: the directive (the way to interpret the datum), and optional arguments such as minimum width specification, justification specification, etc

• this gets complicated, so we will look at examples as we see these various specifiers and options

Page 3: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Simple Directives• ~~ — output a ~• ~% — output a carriage return (start a new line)• ~& — output a fresh line (if we aren’t at the start of a new

line, start a new line)– ~n% and ~n& will output n line breaks/new lines

• ~| — page break, may or may not work depending on the CL system you are using

• ~T – tab, ~nT – tab over n spaces• ~D – output a decimal integer• ~wD – output a decimal integer with at least w characters

(pads the output with blanks)– (format t “~10D” 345) bbbbbbb345 (b = blank)

• ~w,’cD – where c is a character, is the same as ~wD except that the character supplied is used for padding– (format t “~10,’*D” 345) *******345

• ~@D – output the decimal with a + sign for positive (- for negative is always provided with the D argument)

Page 4: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

More Directives• For floating point numbers use:

– ~F – for normal floating point– ~E – for scientific notation– ~G – use ~F or ~E, which ever will provide the shorter notation– ~$ – use monetary notation (as in xxx.xx) but without a dollar sign

• (format t “~$” 32.876) 32.88

• Each of the above permits two width specifiers– the first denotes the total minimum width– the second denotes the number of decimal point digits– the two specifiers are separated by a ,– (format t “~10,2F” 1099.87654) bbb1099.88– (format t “~10,2E” 1099.87654) bbb1.10E+3

• To translate a number into another base you can use:– ~O – octal– ~X – hex– ~B – binary– ~bR – base b integer

• (format t “~6R” 987) 4323• (format t “~X” 1000) 3E8

Page 5: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Yet More Directives!• Here’s where things can get fun:

– ~R – spell an integer out by name• (format t “~R” 987) nine hundred and eighty-seven

– ~:R – add an ending to the spelled out integer like th• (format t “~:R” 987) nine hundred and eighty-seventh

– ~@R – spell out as Roman numerals• (format t “~@R” 987) CMLXXXVII

– ~P – pluralize the output• (format t “~D bottle~P of beer on the wall” X X)

– If X = 1 1 bottle of beer on the wall

– If X = 10 10 bottles of beer on the wall

– If you use ~:P instead of ~P, then you only need to supply the argument once as in (format t “~D bottle~:P of beer on the wall” X)

• ~@P is a variation that chooses whether to use y or ies for an ending

• (format t “do you trust your memor~@P?” X)

Page 6: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Directives for Lists of Values• What if you wanted to supply a list and have each item

output, but you are unsure as you write your statement how many items will appear in the list?– You could use a loop:

• (dolist (x (butlast lis)) (format t “~D, ” x)) (format t “~D” (car (last lis)))

– But format gives you a better way to process a list by using ~{ and ~}

• (format t “~{~D, ~}~D” (butlast lis) (car (last lis)))

• notice that (butlast lis) returns all but the last list item, these are all printed as ~D, or a number followed by a , and a blank, after the list directive ends, we print one more ~D for (car (last lis))

– If we didn’t care about the commas separating the numbers, we could simply to

• (format t “~{~D ~}” lis)

Page 7: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Conditional Printing• Imagine that you don’t know which item to print out of a

list of options, we can use a conditional statement or a conditional directive– Example: You ask the user for a number, 0, 1 or 2, and are

going to print “hello”, “hi”, or “shalom”• (cond ((= x 0) (format t “hello”)) ((= x 1) (format t “hi”)) (t (format t

“shalom”)))– Or you can use the ~[ ~] directive by inserting the options

inside the [ ] as value~;value~;• (format t “~[hello~;hi~;shalom~]” x)

– A binary condition can be presented using ~:[falseoutput~;trueoutput~]

• (format t “you ~:[may not~;may~] drink” (>= age 21)) – You may also supply ~@[format~] which takes the next

argument and, if not nil, processes it, if nil, discards it• (format t “~{~@[~A~]~}” lis) outputs all items in lis one at a time

with the exception of any nil items, which are not output, merely ignored

Page 8: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Characters, Strings and Miscellany• ~C is used to output a character• ~A is used to output strings, but can be used to output any type, so

if you are unsure of the data type, use ~A– ~S is the same as ~A except that escape characters are properly output

• ~( … ~) outputs any text in lower case– ~:@(...~) outputs text in upper case– ~:(…~) outputs text in lower case with each new word capitalized (title

format)– ~@(...~) outputs text in lower case except the first word which is capitalized

(sentence format)

• ~< …~> right justifies whatever is inside the brackets, or– ~w<…~> right justifies to a width of size w (w being an int value)

• ~V forces the next argument to be used as part of the next directive– (format t “~D ~VD ~VD” 10 5 100 8 1000) 10 100 1000

Page 9: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

One Last Example• Imagine that you have two lists: names and addresses

– You want to output them row by row in name/address pairs– You can write a loop to accomplish this:

• (dotimes (i (length names)) (format t "~%~A~10T~A" (nth i names) (nth i addresses)))

– But you could not do this:• (format t “~%~{~A~10T~A~}” names addresses)• because the ~{ ~} empties one list, so you would wind up getting

the first 2 names on one line, the next two on the next line, etc, and no addresses

– However, you can get around that problem by pairing up the two lists

• (setf temp nil)• (dotimes (i (length names)) (setf temp (append temp (list (nth i

names)) (list (nth i addresses)))))• (format t “~{~%~A~10T~A~}” temp)

Page 10: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

The Last Word on Format• All of our examples to this point have used t as

the first parameter to format– This indicates that the output should be sent to the

standard-output stream, which is the same stream that print uses

– So now we have a better way to output than print– We can use different arguments for this parameter

• (setf x (format nil “…”)) returns a string which in this case is stored in x

• (format *new-stream* “…”) outputs to *new-stream*– what is *new-stream*? it is a stream that has been defined

elsewhere in the code and could represent other windows or files– so next, we look at defining and using streams

Page 11: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Using Streams• All of the input and output instructions can take a stream

as an argument and the input/output will be directed to that stream– Built-in streams are:

• *standard-input* -- this is what read defaults to using, and is the keyboard in most systems

• *standard-output* -- this is what print and format default to using, and is the REPL environment in most systems

• *error-output* -- all error messages are sent here, it defaults to *standard-output* but can be redirected, to say a file or another window

• *query-io* -- any user-prompt functions send output here and echo input here, this is the case with the function yes-or-no-p, defaults to a pop-up window in LispWorks

• *debug-io* -- interactive debugging, defaults to *standard-output* in most cases

• *trace-output* -- used by the trace function• *standard-input* and *standard-output* are usually assigned to

*terminal-io*, which is the system’s default input and output (keyboard/monitor)

Page 12: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Input Functions• We’ve seen read, but in reality it is more complex:

– (read &optional input-stream eof-error-p eof-value recursive-p)• ignoring the last item, eof-error-p returns whether an error arose or not and eof-

value contains the type of error• input-stream is whatever stream you want to redirect the input from, for

instance a file

– read-preserving-whitespace – is read but where whitespace is preserved in the input (this allows code to examine the input and see if it was terminated by a space, an enter key, or other) – whitespace by the way is not just blank spaces, it includes the tab key, enter key, etc

– read-line – inputs all characters up to a new line, often used for input from text file

– read-char – input a single character– unread-char – for a text file, resets the file pointer to be one previous (in

effect, nullifies the most recent read-char operation)– peek-char – returns the next character, but leaves file pointer at the current

location• Like read, all of these can have an optional stream to redirect the input and the

non-char functions also allow the other optional params (eof, etc)

Page 13: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Output Functions• As with input functions, all of these (including print) can

take an optional output stream– Without the output stream, it defaults to *standard-output*

• (print object stream)• prin1 is the same as print but print automatically outputs a new line

character first, prin1 does not• princ is the same as prin1 except that all escape characters are suppressed• pprint is the same as print except that trailing space is omitted• both prin1 and print are appropriate to generate output that can be read

by a read statement, princ cannot

– There are also a group of write functions• (write object :stream stream) however these also have several other

keyword arguments available:– :escape, :radix, :base, :circle, :pretty, :level, :length, :case, :gensym, :array– we won’t cover what most of these do, but :circle set to nil means that if a

list has circularity, then the output will stop after one traversal of the list rather than infinitely repeating it!

• in addition, there are write-char, write-string, write-line, prin1-to-string, princ-to-string functions

Page 14: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Miscellany• yes-or-no-p, y-or-n-p – as stated earlier, this function allows you

to send a string prompt to the user and receive a yes or no reply– the first function expects the word “yes” or “no”, the latter can take

characters or words, both will return T if yes/y is typed in (or clicked if a window pops up) or nil

• parse-integer – accepts a string that should be an integer in quotes and returns the appropriate integer value– permits keyword parameters :start, :end :radix, :junk-allowed

• assume date stores a date as “xx/xx/xxxx”, we want to add one to the year:– (+ (parse-integer date :start 6) 1) – without :end, it goes from the start point onward

• clear-input – clears any buffer associated with the given input stream

• terpri – outputs a new line to the given stream– fresh-line – outputs a new line if we aren’t already at the beginning of a

new line• finish-output, force-output and clear-output are all available

similar to clear-input• read-byte, write-byte – to input/output bytes (binary values)

from/to a binary file instead of a text file

Page 15: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Files• Like Java, CL allows you to open, write to/read from, and

close files using streams– To open a file, use (open filename)

• Open has keyword arguments for :direction :element-type :if-exists and :if-does-not-exist

– :direction expects one of :input, :output, :io, :probe (does the file exist? without opening it)

– :element-type allows you to specify the expected type of datum to be input/output from/to this file, these types are recognized: character, integer, string-char, bit and :default

– :if-exists and :if-does-not-exist allow you to specify what to do if the file exists/does not exist: :error, :new-version, :rename, :rename-and-delete, :overwrite, :append, :create, :supersede, nil (don’t do anything, simply return nil as failure)

• Open returns the open stream, but in order to access it you need to store the stream as in (setf infile (open “…” :direction :input :if-does-not-exist nil))

– To close a file, (close stream)– To access the stream, use any of the input or output functions,

specifying the stream in the function as in (read infile)

Page 16: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Example• Imagine that you have an input file that consists of

numeric data– You want to input each datum and output it to another text

file with a description of each datum (for instance, “this is the tenth datum: 31”)

– The following code will do this

(setf infile (open "c:\\csc375\\data.txt"))(setf outfile (open "c:\\csc375\\output.txt"

:direction :output :if-exists :supersede))(do ((i 1 (+ 1 i)) (temp (read infile nil t) (read infile nil t))) ((not (numberp temp))) (format outfile “This is the ~:R datum: ~A~%" i temp))(close infile)(close outfile)

Page 17: Formatted I/O The read and print statements are very limited –they default to using the standard input and output devices –if we want to redirect I/O,

Other Stream Functions• with-open-file: this allows you to open a file in a block such that

any I/O operations in the block default to using the stream you have opened

• rename-file: allows you to rename a file to a new name• delete-file: allows you to delete a given file• file-position: returns the current position, or allows you to change

the current position• probe-file: allows you to determine if a file currently exists by the

given name• file-write-date: returns the file system’s date/time that a given file

was created or last written to• file-author: same but returns the author of the file• file-length: returns the length of a given file as an integer (if the

file is a binary file, this is the number of units as measured by the argument :element-type)

• load: this loads the given filename into the CL environment, interpreting each item in the file as they are read in– this allows you to write functions and other definitions in a file and load

them in prior to starting a given session