Бармар ответ правильный. Для интереса, вот версия read-and-parse
, которая, возможно, более идиоматично использует loop
, а также абстрагирует решение «является символом белого», поскольку это действительно нереально в портативном CL, так какстандартный репертуар персонажей абсурдно скуден (например, нет вкладки!). Я уверен, что есть некоторая библиотека, доступная через Quicklisp , которая справляется с этим лучше, чем приведенная ниже.
Я думаю, что это вполне читабельно: есть внешний цикл, который собирает слова, и внутреннийцикл, который собирает символы в слово, пропуская пробелы, пока не найдет следующее слово. Оба используют функцию loop
collect
для сбора списков вперед. С другой стороны, я чувствую себя немного плохо каждый раз, когда я использую loop
(я знаю, что есть альтернативы).
По умолчанию это собирает слова в виде списков символов: если вы скажете это, он соберетих как строки.
(defun char-white-p (c)
;; Is a character white? The fallback for this is horrid, since
;; tab &c are not a standard characters. There must be a portability
;; library with a function which does this.
#+LispWorks (lw:whitespace-char-p c)
#+CCL (ccl:whitespacep c) ;?
#-(or LispWorks CCL)
(member char (load-time-value
(mapcan (lambda (n)
(let ((c (name-char n)))
(and c (list c))))
'("Space" "Newline" "Page" "Tab" "Return" "Linefeed"
;; and I am not sure about the following, but, well
"Backspace" "Rubout")))))
(defun read-and-parse (filename &key (as-strings nil))
"Parse a file into a list of words, splitting on whitespace.
By default the words are returned as lists of characters. If
AS-STRINGS is T then they are coerced to strings"
(with-open-file (s filename)
(loop for maybe-word = (loop with collecting = nil
for c = (read-char s nil)
;; carry on until we hit EOF, or we
;; hit whitespace while collecting a
;; word
until (or (not c) ;EOF
(and collecting (char-white-p c)))
;; if we're not collecting and we see
;; a non-white character, then we're
;; now collecting
when (and (not collecting) (not (char-white-p c)))
do (setf collecting t)
when collecting
collect c)
while (not (null maybe-word))
collect (if as-strings
(coerce maybe-word 'string)
maybe-word))))