小lisp挑战

时间:2014-08-14 05:20:06

标签: lisp

我有一个像" 2d 6:36"这样的字符串,我希望将这个小时数乘以常数。

这意味着我想要计算:

(2*24 + 6 + 36/60) * constant

或者,通常

(d*24 + h + m/60)

任何帮助?

编辑:我只有字符串而不是d,h和m。

2 个答案:

答案 0 :(得分:1)

您需要在有用的内容中解析字符串,例如整数列表,您可以使用cl-ppcre

(defun parse-day-and-time (string)
  "Get string like 3d 23:40 and return list (3 23 40)"
  (multiple-value-bind (str matches)
    (cl-ppcre:scan-to-strings "(\\d+)d ([0-9]|0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])" string)
    (declare (ignore str))
    (when (< (length matches) 3)
      (error "Wrong day and time string: ~A" string))
    (map 'list #'parse-integer matches)))

然后你可以做你的计算:

(defun mult-time (string-time coeff)
  (destructuring-bind (days hours minutes)
    (parse-day-and-time string-time)
    (* coeff (+ (* 24 days) hours (/ minutes 60)))))

CL-USER> (mult-time "2d 6:36" 300)
16380

原因如果你想用你的时间做更多的计算,可能最好将它表示为秒数,用它计算,然后用你想要的任何字符串返回它。

答案 1 :(得分:1)

所以我理解数据是人类可读的时间量。例如。 &#34; 2d 1:35&#34;表示2天,1小时35秒或595/12小时。我很想放弃字符串的规范,如下所示:

(defparameter *units* '(("w" . 168) ("d" . 24) (":" . 1)
                        ("h" . 1) ("m" . 1/60) ("s" . 1/3600)))
(defun str-to-hours (str &optional (acc 0))
  (or
   (cl-ppcre:register-groups-bind (num unit rest)
                                  ("(\\d+)\\s*(\\D{0,1})\\D*(.*)" str :sharedp t)
     (str-to-hours rest
                   (+ acc
                      (* (parse-integer num)
                         (or (cdr (assoc (string-downcase unit) 
                                         *units* 
                                         :test #'equal)) 
                              1/60)))))
   acc))

(str-to-hours  "2d 6:36")  ; ==> 273/5 ~54.6
(str-to-hours  "2D6H36M")  ; ==> 273/5 ~54.6
(str-to-hours  "2 weeks, 1 day, 3 hours, 7 minutes and 10 seconds") ; ==> 130723/360 ~363.11945

(* 10 (str-to-hours "2d6:36")) ; ==> 546