More complicated input from files

November 16, 2009
by Lee Spector (lspector)

In an earlier post I showed how to open a file and to read a single item of Scheme data from it. (By the way, in the earlier post I used the phrase “Scheme object” to mean a single item of Scheme data, meaning an atom or a list — the kinds of data we’ve been manipulating in Scheme all along. Don’t confuse this with the more specialized and non-standard “object” things that are part of PLT Scheme’s object-oriented programming support. I’ve used those specialized objects occasionally in our graphics code, but we haven’t gone over them in any systematic way in class.)

But suppose that you want to open and read from a text file that contains more than one Scheme data item, and in fact maybe it contains special characters that you want to handle in some unusual way, etc. What to do?

The main thing that you’ll want to know about is “read-line”. This is like “read” except that it returns what it read as a string of characters, not as an atom or list, etc., and it reads until it finds a line separator or the end of the file. You can call it repeatedly to read multiple lines. See section 12.2 of the PLT reference for details.

Once you’ve read in the string you can do a variety of things with it. If you just want the string to remain a string then you’re done. You can look at characters in the string with the string-ref procedure, or use other string-manipulating procedures to modify it or produce new strings based on the contents, etc. By the way, the “format” procedure is particularly handy for forming new strings — it’s like “printf” except that it returns a string instead of printing it.

But what if you then want to read the resulting string as an ordinary Scheme data item? For example, suppose you read a line of a file that contains a bunch of numbers using read-line. Then the result of read-line will actually be a string of characters that represent the numbers and spaces, not actual numbers. Suppose you put this in the variable nums-in-string. You could then do something like:

(set! list-in-string (format "(~A)" nums-in-string))

to create a new string that now contains an open “(“, followed by the characters representing all of the numbers and spaces, followed by a close “)”. But it’s still just a string of characters. How do you get normal Scheme data out of that?

The answer is that “read” can also take an argument, which must be a port, and that you can make a port from a string using “open-input-string”. So that means that you can do:

(read (open-input-string list-in-string))

and that this will return a list of numbers, as normal Scheme data (not as a string of characters).


Leave a Reply

You must be logged in to post a comment.