在 Common Lisp 中将数字格式化为特定格式
Formatting number to specific format in 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++ 版本几乎相同。
谢谢!
一个简单的解决方案是将秒分成它们自己的组成部分,例如小时和分钟。我还使用 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"
我没有检查是否有足够的毫秒数来计算小时或分钟。无论如何,数学都算出来了,我无法想象额外的计算会成为瓶颈。
关于风格(功能改进见jkiiski的回答):
- 不需要
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))
我可能会使用 floor
returns 两个值(除法的整数部分,以及提醒)这一事实来做到这一点。
(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)))))
我想将整数(毫秒)转换为以下格式:
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++ 版本几乎相同。
谢谢!
一个简单的解决方案是将秒分成它们自己的组成部分,例如小时和分钟。我还使用 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"
我没有检查是否有足够的毫秒数来计算小时或分钟。无论如何,数学都算出来了,我无法想象额外的计算会成为瓶颈。
关于风格(功能改进见jkiiski的回答):
- 不需要
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))
我可能会使用 floor
returns 两个值(除法的整数部分,以及提醒)这一事实来做到这一点。
(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)))))