在Common Lisp中将数字格式化为特定格式

时间:2016-04-27 18:08:50

标签: common-lisp

我想将整数(毫秒)转换为以下格式:

HH:MM:SS,SSS

例如时间戳12,5秒是00:00:12,500,1小时38分10秒就像01:38:10,000一样。

我是Lisp编程的新手,但这是我到目前为止所做的。

(defun ms->time (ms)
  (let ((hours 0)
        (minutes 0)
        (seconds ms))
    (progn
      (and (>= seconds 3600000)
           (progn
             (setq hours (floor (/ seconds 3600000)))
             (setq seconds (mod seconds 3600000))))
      (and (>= seconds 60000)
           (progn
             (setq minutes (floor (/ seconds 60000)))
             (setq seconds (mod seconds 60000))))
    (format nil "~2,'0d:~2,'0d:~6,'0:d" hours minutes seconds))))

这是简单的输出:

CL> (ms->time 12500)
"00:00:12,500"
CL> (ms->time 5890000)
"01:38:10,000"

看起来很棒,完全按照我的意愿。然而...

CL> (ms->time 0)
"00:00:000000"    
CL> (ms->time 999)
"00:00:000999"

如何解决此问题? format非常先进,我很确定有办法做我需要的事情。当然,如果你有任何想法如何改变我的功能,请更多 lispy - 请不要犹豫。我目前的方法与我的C ++版本几乎相同。

谢谢!

3 个答案:

答案 0 :(得分:4)

一个简单的解决方案是将秒分成他们自己的组件,如小时和分钟。我还使用LET*来隐藏MS,以避免出现SETQ个变量:

(defun ms->time (ms)
  (let* ((hours (floor ms 3600000))
         (ms (mod ms 3600000))
         (minutes (floor ms 60000))
         (ms (mod ms 60000))
         (seconds (floor ms 1000))
         (ms (mod ms 1000)))
    (format nil "~2,'0d:~2,'0d:~2,'0d,~3,'0d"
            hours minutes seconds ms)))

(ms->time 0)
;=> "00:00:00,000"
(ms->time 999)
;=> "00:00:00,999"

我遗漏了检查是否有足够的毫秒来制作小时或分钟。数学运算无论如何,我无法想象额外的计算是一个瓶颈。

答案 1 :(得分:4)

关于风格(请参阅jkiiski&#39的功能改进答案):

    PROGN
  • 不需要LET
  • 以这种方式使用AND是不寻常的,避免
  • (floor (/ x a))(floor x a)

您的代码可以写得更短。

  • top函数变量可以在arglist中指定为&aux。通过删除LET
  • ,这可以用于删除一层括号
  • WHEN代替AND
  • SETF代替SETQ - 它可以设置多个地方

示例

(defun ms->time (ms &aux (hours 0) (minutes 0) (seconds ms))
  (when (>= seconds 3600000)
    (setf hours   (floor seconds 3600000)
          seconds (mod seconds 3600000)))
  (when (>= seconds 60000)
    (setf minutes (floor seconds 60000)
          seconds (mod seconds 60000)))
  (format nil "~2,'0d:~2,'0d:~6,'0:d" hours minutes seconds))

答案 2 :(得分:3)

我可能会通过使用floor返回两个值(除法的整数部分以及提醒)这一事实来做到这一点。

(defun ms->time (ms &optional (stream nil))
  (multiple-value-bind (rest ms) (floor ms 1000)
    (multiple-value-bind (rest s) (floor rest 60)
      (multiple-value-bind (h m) (floor rest 60)
        (format stream "~2,'0d:~2,'0d:~2,'0d,~3,'0d" h m s ms)))))