我正在尝试在lisp中实现一个函数read-from-whole-string
,它使用内置函数read-from-string
。
read-from-string
read-from-string用于从字符串中读取对象,可以使用关键字:start
,:end
等指定对象。它返回两个值,即对象和下一个的位置元素,没有读过。我计划使用这个值。
计划是使用从read-from-string
函数返回的第二个值,再次使用它来插入关键字:start
的值。但问题是函数multiple-value-bind。我们不能:
multiple-value-bind
中初始化变量。 values-form
的变量。 具体来说,我想:
(multiple-value-bind (x (y 0))
(read-from-string str :Start y)
y)
赞赏任何其他干净的方法。
答案 0 :(得分:3)
CL-USER 118 > (let ((string "10 2 300 foo \"bar\""))
(loop with pos and value
for start = 0 then pos
do (setf (values value pos)
(read-from-string string nil string :start start))
while (not (eq value string))
collect value))
(10 2 300 FOO "bar")
CL-USER 120 > (let ((string "10 2 300 foo \"bar\""))
(loop for start = 0 then pos
for (value pos) = (multiple-value-list
(read-from-string string nil string
:start start))
while (not (eq value string))
collect value))
(10 2 300 FOO "bar")
答案 1 :(得分:2)
你可以创建一个字符串流,读取并丢弃一个对象,然后再读一遍:
$ clisp -q
[1]> (with-input-from-string (*standard-input* "1 2") (read) (read))
2
要读取输入字符串中的所有元素,我们可以在read
上循环并使用唯一值来检测EOF,而不是让它抛出错误:
(with-input-from-string (s "1 2 3 4")
(loop with eof = '#:eof
for item = (read s nil eof)
until (eq item eof)
collecting item))
-> (1 2 3 4)
要提取字符串中的所有对象,我们还可以将其包装在括号中并使用read-from-string
的单个应用程序:
(read-from-string (format nil "(~a)" "1 2 3 4"))
-> (1 2 3 4); 11
当字符串包含此类问题时,存在缺乏诊断的危险:"a b ) c d"
。我们可以通过将返回的长度与字符串长度进行比较来检查这种情况,以确保所有内容都被读取,如果不是,则发出一些通用诊断。
(defun read-whole-string (str)
(let ((par-str (format nil "(~a)" str)))
(multiple-value-bind (obj len) (read-from-string par-str)
(if (eql len (length par-str))
obj
(error "read-whole-string: ~a is malformed at position ~s"
str (- len 2))))))
答案 2 :(得分:0)
实现函数read-from-whole-string
的其他方法可能不太干净:
(defun read-from-whole-string (str)
(loop
collect (multiple-value-bind (x y)
(read-from-string str)
(setf str (delete-if #'atom str :start 0 :end (if (= (length str) y)
y
(1- y))))
x)
until (zerop (length str))
))