Лисп: Как подсказать-прочитать поплавок? - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть функция, где я использую parse-integer и prompt-read вместе. Тем не менее, мне нужно одно из этих целых чисел, чтобы быть с плавающей точкой. Когда я изменяю 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))))  

Это работает как есть, но мне нужно, чтобы первое целое число, "Вес", было числом с плавающей точкой. parse-float не работает, и я не могу найти правильный способ сделать это.

Ответы [ 2 ]

2 голосов
/ 05 февраля 2020

Есть два подхода к этому. Одним из них является использование 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 , которая решает эту проблему для вас. Эта библиотека доступна через Quicklisp . Предполагая, что у вас установлен Quicklisp (который у вас должен быть: если нет, то ваша первая проблема заключается в том, чтобы это было правдой), тогда используйте это так же просто, как сказать (ql:quickload "parse-float"), а затем выполнить синтаксический анализ, например:

> (parse-float:parse-float "12.2")
12.2
4
1 голос
/ 05 февраля 2020
(let ((weight (progn
                (format t "Weight: ")
                (read t))))
  (if (floatp weight) weight 0))
...