Subject: Re: Formatting: separating commas for non-decimals
From: Erik Naggum <>
Date: 1999/11/15
Newsgroups: comp.lang.lisp
Message-ID: <>

* Robert Monfera <>
| I needed to format a number such that there are separating commas at
| every third digit (dollars), and two decimals for the cents:

(in-package :cl-user)

(declaim (declaration :author :date :copyright))
(declaim (:author "Erik Naggum")
	 (:date "1997-08-12")
	 (:copyright "Copyright 1997 by Erik Naggum.
Any use is permitted provided that this copyright notice is retained and
that all changes are duly identified."))

(defun dollars (stream amount colon-p atsign-p
		&optional (width 0) (padchar #\Space) (commachar #\,))
  "Print an amount of dollars for humans to read from FORMAT.

The full form is ~WIDTH,PADCHAR,COMMACHAR:@/DOLLARS/, where WIDTH is the
minimum width of the field (default 0), PADCHAR is the character used to
pad to the width on the left end, and COMMACHAR is the separator between
each group of three digits.

The @ modifier controls printing of the sign of positive amounts.  If
omitted, a positive value prints without a sign.  Otherwise, a positive
amount has an explicit + sign.

The : modifier controls the position of the sign and the padding.  If
omitted, the dollar sign is printed in the leftmost position, then any
intervening pad characters, then the signed value.  Otherwise, the sign
occupies the leftmost position, and the dollar sign follows any intervening
pad characters."
  (let* ((digits 
	  (multiple-value-bind (dollars cents) (floor (abs amount) 1)
	    (format nil "~,,V:D.~2,'0D" commachar dollars (round cents 0.01))))
	 (sign (if (minusp amount) #\- (if atsign-p #\+ nil)))
	 (padding (max 0 (- width 1 (if sign 1 0) (length digits))))
	 (pre (if colon-p sign #\$))
	 (post (if colon-p #\$ sign)))
    (when pre (write-char pre stream))
    (dotimes (i padding) (write-char padchar stream))
    (when post (write-char post stream))
    (write-string digits stream)))

  Attention Microsoft Shoppers!  MS Monopoly Money 6.0 are now worthless.