2011-06-15 10 views
11

¿Hay una manera simple de alinear en el punto decimal una columna de flotadores? En otras palabras, me gustaría una salida como la de (barras verticales '|' están allí sólo para fines de claridad)Flotantes alineados verticales en el punto decimal

(format t "~{|~16,5f|~%~}" '(798573.467 434.543543 2.435 34443.5)) 

que es

| 798573.44000| 
|  434.54355| 
|   2.43500| 
|  34443.50000| 

pero con espacios a la derecha en lugar de ceros, de la siguiente manera:

| 798573.44 | 
|  434.54355| 
|   2.435 | 
|  34443.5 | 

Respuesta

5

no creo que esto se puede hacer fácilmente con caracteres de control incorporadas format 's, pero se puede pasar su propia función a ella:

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

Usted puede utilizar de esta manera:

defecto de carácter
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 

el relleno a #\Space, y puede ser dada como un tercer argumento así: "~16,5,' /my-f/".

Una implementación alternativa usando 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))) 

(Negación: Tal vez me daba algo más fácil en la documentación de format.)

+2

creo "elegancia" gana con el pretexto de que esto se puede hacer en absoluto dentro del marco de 'formato' simplemente añadiendo una función en lugar de tener que tirar el kit completo. –

+0

Will, quise decir mi implementación de 'my-f', que tal vez podría hacerse mejor. Por ejemplo, probablemente no debería soltar el '0' de' 1.0'. Claro, es bueno que 'format' sea tan flexible! – danlei

+0

Algo extraño, ¿por qué 798573.467 se muestra como 798573.44? (Esto sucede en formato simple también) @danlei – mmj

Cuestiones relacionadas