Lisp:如何提示阅读浮点数?

Lisp: How to prompt-read a float?

我有一个函数,我同时使用解析整数和提示阅读。但是,我需要这些整数之一是浮点数。当我将 parse-integer 更改为 parse-float 时,它不再有效。 这是函数:

(defun prompt-for-cat ()                                                       
  (add-record                                                                  
    (make-cat                                                                    
      (prompt-read "Name")                                                        
      (prompt-read "Coloring")                                                    
      (or (parse-integer (prompt-read "Weight") :junk-allowed t) 0)               
      (or (parse-integer (prompt-read "Experience") :junk-allowed t) 0)           
      (or (parse-integer (prompt-read "Length") :junk-allowed t) 0))))  

这按原样工作,但我需要第一个整数,"Weight" 是一个浮点数。 parse-float 不起作用,我找不到正确的方法来做到这一点。

(let ((weight (progn
                (format t "Weight: ")
                (read t))))
  (if (floatp weight) weight 0))

有两种方法可以做到这一点。一种是以某种形式使用 read,另一种是使用浮点解析库。

使用read

委婉地说,使用 read 充满了危险。特别是,除非您小心,否则您很容易受到代码注入攻击。 切勿在您不完全信任输入的代码中使用 read,除非您至少对其采取了一些安全预防措施。

就是说,这里有一个函数尝试以最低限度安全的方式使用 read 来读取带提示的浮点数。

(defun prompt-for-float (prompt &optional (default 0.0))
  ;; Use READ to read a float, in a way which should be at least
  ;; minimally safe.
  (with-standard-io-syntax
    (let ((*read-eval* nil))
      (format *query-io* "~A: " prompt)
      (finish-output *query-io*)
      (let ((result (read *query-io*)))
        (typecase result
          (float result)
          (real (coerce result 'float))
          (t default))))))

这至少 尝试 通过标准化语法和关闭读取时评估来提高安全性,代码注入攻击就是这样发生的。

然而,这可能仍然不是完全安全的。除了可能不安全之外,在允许在系统上执行不受控制的代码的意义上,使用 read 没有严格约束的可读表也不是没有副作用的(例如,它可以实习符号) ,并且可以允许各种可能的拒绝服务攻击,例如通过导致大量内存分配。要处理这些问题,您要么需要做大量工作,将可读表减少到安全的范围,要么使用只读取您关心的类型的库。

使用浮点解析库

有一个名为 parse-float which solves this problem for you. This library is available via Quicklisp 的图书馆。假设你安装了 Quicklisp(你应该安装:如果没有,那么你的第一个问题是安排它是真的),那么使用它就像说 (ql:quickload "parse-float") 一样简单,然后解析浮点数,对于实例:

> (parse-float:parse-float "12.2")
12.2
4