unread-char
unread-char Function
Syntax:
unread-char character &optional input-stream → nil
Arguments and Values:
character—a character ; must be the last character that was read from input-stream. input-stream—an input stream designator . The default is standard input.
Description:
unread-char places character back onto the front of input-stream so that it will again be the next character in input-stream.
When input-stream is an echo stream, no attempt is made to undo any echoing of the character that might already have been done on input-stream. However, characters placed on input-stream by unread-char are marked in such a way as to inhibit later re-echo by read-char.
It is an error to invoke unread-char twice consecutively on the same stream without an intervening call to read-char (or some other input operation which implicitly reads characters) on that stream.
Invoking peek-char or read-char commits all previous characters. The consequences of invoking unread-char on any character preceding that which is returned by peek-char (including those passed over by peek-char that has a non-nil peek-type) are unspecified. In particular, the consequences of invoking unread-char after peek-char are unspecified.
Examples:
(with-input-from-string (is "0123")
(dotimes (i 6)
(let ((c (read-char is)))
(if (evenp i) (format t "~&~S ~S~%" i c) (unread-char c is)))))
▷ 0 #\0
▷ 2 #\1
▷ 4 #\2
→ NIL
Affected By:
*standard-input*, *terminal-io*.
See Also:
peek-char, read-char, Section 21.1 (Stream Concepts)
Notes:
unread-char is intended to be an efficient mechanism for allowing the Lisp reader and other parsers to perform one-character lookahead in input-stream.
Expanded Reference: unread-char
Basic Usage
unread-char puts a character back onto the front of an input stream so it will be the next character read. The character must be the last character that was read from the stream.
(with-input-from-string (s "abc")
(let ((c (read-char s)))
(unread-char c s)
(list c (read-char s))))
=> (#\a #\a)
One-Character Lookahead
unread-char is typically used for implementing parsers that need one-character lookahead.
(with-input-from-string (s "0123")
(dotimes (i 6)
(let ((c (read-char s)))
(if (evenp i)
(format t "~&~S ~S~%" i c)
(unread-char c s)))))
; prints:
; 0 #\0
; 2 #\1
; 4 #\2
=> NIL
Reading Until a Delimiter
A common pattern is to read characters and put back the delimiter.
(with-input-from-string (s "hello world")
(let ((chars (loop for c = (read-char s nil nil)
while (and c (char/= c #\Space))
collect c
finally (when c (unread-char c s)))))
(list (coerce chars 'string)
(read-char s nil nil))))
=> ("hello" #\Space)
Constraint: Only One Unread
You cannot call unread-char twice consecutively without an intervening read operation.
;; This is correct: read, unread, read, unread
(with-input-from-string (s "ab")
(let ((c1 (read-char s)))
(unread-char c1 s)
(let ((c2 (read-char s)))
(list c1 c2))))
=> (#\a #\a)