Reputation: 571
Context:
I have a text file called fr.txt
with 3 columns of text in it:
65 A #\A
97 a #\a
192 À #\latin_capital_letter_a_with_grave
224 à #\latin_small_letter_a_with_grave
etc...
I want to create a function to read the first (and eventually the third one too) column and write it into another text file called alphabet_code.txt
.
So far I have this function:
(defun alphabets()
(setq source (open "fr.txt" :direction :input :if-does-not-exist :error))
(setq code (open "alphabet_code.txt" :direction :output :if-does-not-exist :create :if-exists :supersede))
(loop
(setq ligne (read-line source nil nil))
(cond
((equal ligne nil) (return))
(t (print (read-from-string ligne) code))
)
)
(close code)
(close source)
)
My problems:
I don't really understand how the parameters of read-line function. I have read this doc, but it's still very obscure to me. If someone would have very simple examples, that would help.
With the current code, I get this error: *** - read: input stream #<input string-input-stream> has reached its end
even if I change the nil nil
in (read-line source nil nil)
to other values.
Thanks for your time!
Upvotes: 3
Views: 4011
Reputation: 60054
read-line
optional argumentsread-line
accepts 3 optional arguments:
eof-error-p
: what to do on EOF (default: error)eof-value
: what to return instead of the error when you see EOFrecursive-p
: are you calling it from your print-object
method (forget about this for now)E.g., when the stream
is at EOF,
(read-line stream)
will signal the end-of-file
error(read-line stream nil)
will return nil
(read-line stream nil 42)
will return 42
.Note that (read-line stream nil)
is the same as (read-line stream nil nil)
but people usually still pass the second optional argument explicitly.
eof-value
of nil
is fine for read-line
because nil
is not a string and read-line
only returns strings.
Note also that in case of read
the second optional argument is, traditionally, the stream
itself: (read stream nil stream)
. It's quite convenient.
You are getting the error from read-from-string
, not read-line
, because, apparently, you have an empty line in your file.
I know that because the error mentions string-input-stream
, not file-stream
.
Your code is correct functionally, but very wrong stylistically.
with-open-file
whenever possible.print
in code, it's a weird legacy function mostly for interactive use.setq
- use let
or other equivalent forms (in this case, you never need let
! :-)Here is how I would re-write your function:
(defun alphabets (input-file output-file)
(with-open-stream (source input-file)
(with-open-stream (code output-file :direction :output :if-exists :supersede)
(loop for line = (read-line source nil nil)
as num = (parse-integer line :junk-allowed t)
while line do
(when num
(write num :stream code)
(write-char #\Newline code))))))
(alphabets "fr.txt" "alphabet_code.txt")
See the docs:
Alternatively, instead of (when num ...)
I could have use the corresponding loop
conditional.
Also, instead of write
+write-char
I could have written (format code "~D~%" num)
.
Note that I do not pass those of your with-open-stream
arguments that are identical to the defaults.
The defaults are set in stone, and the less code you have to write and your user has to read, the less is the chance of an error.
Upvotes: 9