假设我有浮点数1234.9
我想将其格式化为1.234,90
是否有格式指令组合? ~D
可以处理分组和组char,只处理整数。 ~F
根本不处理分组。据我所知,没有人可以将小数点从.
更改为,
我看到的唯一解决方案是使用~D
进行整数部分数字分组,并将其与,
和小数部分连接起来。有更好的想法吗?
答案 0 :(得分:4)
正如jkiiski的评论所暗示的那样,你可以使用~/func/
指令。
这只是一个例子,您可以使用以下功能详细说明:
CL-USER> (defun q(stream arg &rest args)
(declare (ignore args))
(format stream
"~,,'.,:D,~a"
(truncate arg)
(let ((float-string (format nil "~f" arg)))
(subseq float-string (1+ (position #\. float-string))))))
Q
CL-USER> (format t "~/q/~%" 1024.36)
1.024,36
NIL
CL-USER> (format t "~/q/~%" -1024.36)
-1.024,36
NIL
被修改
第一个版本有round
,这是错误的,truncate
是正确的操作符。
答案 1 :(得分:4)
你可以定义一个用tilde-slash调用的函数,其中大多数其他答案已经完成了,但是为了得到类似于~F的输出,但是注入了逗号字符,并且替换了小数点,我认为最好调用~F生成的输出,然后修改它并将其写入字符串。这是一种方法,使用实用程序 inject-comma ,将指定间隔的逗号字符添加到字符串。这是指令功能:
(defun print-float (stream arg colonp atp
&optional
(point-char #\.)
(comma-char #\,)
(comma-interval 3))
"A function for printing floating point numbers, with an interface
suitable for use with the tilde-slash FORMAT directive. The full form
is
~point-char,comma-char,comma-interval/print-float/
The point-char is used in place of the decimal point, and defaults to
#\\. If : is specified, then the whole part of the number will be
grouped in the same manner as ~D, using COMMA-CHAR and COMMA-INTERVAL.
If @ is specified, then the sign is always printed."
(let* ((sign (if (minusp arg) "-" (if (and atp (plusp arg)) "+" "")))
(output (format nil "~F" arg))
(point (position #\. output :test 'char=))
(whole (subseq output (if (minusp arg) 1 0) point))
(fractional (subseq output (1+ point))))
(when colonp
(setf whole (inject-comma whole comma-char comma-interval)))
(format stream "~A~A~C~A"
sign whole point-char fractional)))
以下是一些例子:
(progn
;; with @ (for sign) and : (for grouping)
(format t "~','.2@:/print-float/ ~%" 12345.6789) ;=> +1.23.45,679
;; with no @ (no sign) and : (for grouping)
(format t "~'.'_3:/print-float/ ~%" 12345.678) ;=> 12_345.678
;; no @ (but sign, since negative) and : (for grouping)
(format t "~'.'_3:/print-float/ ~%" -12345.678) ;=> -12_345.678
;; no @ (no sign) and no : (no grouping)
(format t "~'.'_3@/print-float/ ~%" 12345.678)) ;=> +12345.678 (no :)
以下是来自coredump-'s answer的示例,它实际上帮助我捕获了负数的错误:
CL-USER> (loop for i in '(1034.34 -223.12 -10.0 10.0 14 324 1020231)
do (format t "~','.:/print-float/~%" i))
1.034,34
-223,12
-10,0
10,0
14,0
324,0
1.020.231,0
NIL
这是 inject-comma ,有一些例子:
(defun inject-comma (string comma-char comma-interval)
(let* ((len (length string))
(offset (mod len comma-interval)))
(with-output-to-string (out)
(write-string string out :start 0 :end offset)
(do ((i offset (+ i comma-interval)))
((>= i len))
(unless (zerop i)
(write-char comma-char out))
(write-string string out :start i :end (+ i comma-interval))))))
(inject-comma "1234567" #\, 3)
;;=> "1,234,567"
(inject-comma "1234567" #\. 2)
;;=> "1.23.45.67"
答案 2 :(得分:1)
其他答案目前使用round
,这可能不是向上舍入(正数)或向下(负数)时的预期行为。这是~/custom/
指令的另一种方法,主要来自Renzo的答案。
(defun custom (stream number &rest args)
(declare (ignore args))
(multiple-value-bind (integer decimal) (truncate number)
(format stream "~,,'.,:D~@[,~a~]"
integer
(unless (zerop decimal)
(let ((decimal-string (princ-to-string (abs decimal))))
(subseq decimal-string (1+ (position #\. decimal-string))))))))
(loop for i in '(1034.34 -223.12 -10.0 10.0 14 324 1020231)
collect (custom nil i))
=> ("1.034,33996582" "-223,11999512" "-10" "10" "14" "324" "1.020.231")
答案 3 :(得分:0)
如果您不介意拆分整数和小数部分,您可以执行以下操作:
(multiple-value-bind (int rest) (floor 1234.56)
(let ((rest (round (* rest 1000))))
(format t "~,,'.,:D,~D~%" int rest)))
1.234,560
舍入前的乘法表示您想要打印逗号后的位数。不确定这种方法是否适合自动控制精密印刷,即1.5
印刷为" 1,5"而不是" 1,500"。