垂直对齐浮在小数点上

| 有没有一种简单的方法可以将一列浮点数在小数点上对齐?换句话说,我想要一个类似以下的输出(竖线\'| \'仅用于清晰目的)
(format t \"~{|~16,5f|~%~}\" \'(798573.467 434.543543 2.435 34443.5))
这是
|    798573.44000|
|       434.54355|
|         2.43500|
|     34443.50000|
但尾随空格而不是零,如下所示:
|    798573.44   |
|       434.54355|
|         2.435  |
|     34443.5    |
    
已邀请:
        我认为使用
format
的内置控制字符不容易做到这一点,但是您可以将自己的函数传递给它:
(defun my-f (stream arg colon at &rest args)
  (declare (ignore colon at))
  (destructuring-bind (width digits &optional (pad #\\Space)) args
    (let* ((string (format nil \"~v,vf\" width digits arg))
           (non-zero (position #\\0 string :test #\'char/= :from-end t))
           (dot (position #\\. string :test #\'char= :from-end t))
           (zeroes (- (length string) non-zero (if (= non-zero dot) 2 1)))
           (string (nsubstitute pad #\\0 string :from-end t :count zeroes)))
      (write-string string stream))))
您可以像这样使用它:
CL-USER> (format t \"~{|~16,5/my-f/|~%~}\" \'(798573.467 434.543543 2.435 34443.5 10))
|    798573.44   |
|       434.54355|
|         2.435  |
|     34443.5    |
|        10.0    |
NIL
填充字符默认为
#\\Space
,并且可以作为第三个参数给出,如
\"~16,5,\' /my-f/\"
。 使用
loop
的替代实现:
(defun my-f (stream arg colon at &rest args)
  (declare (ignore colon at))
  (loop with string = (format nil \"~v,vf\" (car args) (cadr args) arg)
        and seen-non-zero = nil
        for i from (1- (length string)) downto 0
        as char = (char string i)
        if (char/= char #\\0) do (setq seen-non-zero t)
        collect (if (and (not seen-non-zero)
                         (char= char #\\0)
                         (not (char= #\\. (char string (1- i)))))
                    (or (caddr args) #\\Space)
                    char) into chars
        finally (write-string (nreverse (coerce chars \'string)) stream)))
(免责声明:也许我在ѭ3documentation的文档中忽略了一些容易的事情。)     

要回复问题请先登录注册