Выравнивание по вертикали плавает на десятичной точке - PullRequest
11 голосов
/ 15 июня 2011

Есть ли простой способ выровнять по десятичной точке столбец с плавающей точкой?Другими словами, я хотел бы получить вывод, подобный выходу (вертикальные столбцы '|' существуют только для ясности)

(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    |

1 Ответ

5 голосов
/ 16 июня 2011

Я не думаю, что это легко сделать с помощью встроенных управляющих символов 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)))

(Отказ от ответственности: Может быть, я упустил что-то более простое в документации format.)

...