From: Don Geddis
Subject: FORMAT & abbreviated ordinals
Date: 
Message-ID: <873avptfk1.fsf@geddis.org>
So if I do
        (format t "~:R" 4)
I get
        fourth
but I want
        4th

Any of you FORMAT wizards know a simple way to print abbreviated ordinals?

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
Statisticians are people who like figures, but don't have the personality
skills to become accountants.  -- Peter Donnelly, TED (Jun 25, 2007)

From: Rob Warnock
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <BcGdnbpMXth1WLfanZ2dnUVZ_tSknZ2d@speakeasy.net>
Don Geddis  <···@geddis.org> wrote:
+---------------
| So if I do   (format t "~:R" 4)
| I get        fourth
| but I want   4th
| Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
+---------------

Not using "~R" per se, but I once had occasion to need the same
thing, and I did it something like this [though ISTR that I may
have used an AREF on a vector of 10 strings instead of the CASE]:

    > (defun ordinal-suffix (n)
	(let ((n (mod n 100)))
	  (if (<= 11 n 13)    ; special-case English-language rule
	    "th"
	    (let ((which (mod n 10)))
	      (case which
		((1) "st")
		((2) "nd")
		((3) "rd")
		(t "th"))))))

    ORDINAL-SUFFIX
    > (loop for i to 225
	collect (format nil "~d~a" i (ordinal-suffix i)))

    ("0th" "1st" "2nd" "3rd" "4th" "5th" "6th" "7th" "8th" "9th"
     "10th" "11th" "12th" "13th" "14th" "15th" "16th" "17th" "18th"
     "19th" "20th" "21st" "22nd" "23rd" "24th" "25th" "26th" "27th"
     "28th" "29th" "30th" "31st" "32nd" "33rd" "34th" "35th" "36th"
     "37th" "38th" "39th" "40th" "41st" "42nd" "43rd" "44th" "45th"
     "46th" "47th" "48th" "49th" "50th" "51st" "52nd" "53rd" "54th"
     "55th" "56th" "57th" "58th" "59th" "60th" "61st" "62nd" "63rd"
     "64th" "65th" "66th" "67th" "68th" "69th" "70th" "71st" "72nd"
     "73rd" "74th" "75th" "76th" "77th" "78th" "79th" "80th" "81st"
     "82nd" "83rd" "84th" "85th" "86th" "87th" "88th" "89th" "90th"
     "91st" "92nd" "93rd" "94th" "95th" "96th" "97th" "98th" "99th"
     "100th" "101st" "102nd" "103rd" "104th" "105th" "106th" "107th"
     "108th" "109th" "110th" "111th" "112th" "113th" "114th" "115th"
     "116th" "117th" "118th" "119th" "120th" "121st" "122nd" "123rd"
     "124th" "125th" "126th" "127th" "128th" "129th" "130th" "131st"
     "132nd" "133rd" "134th" "135th" "136th" "137th" "138th" "139th"
     "140th" "141st" "142nd" "143rd" "144th" "145th" "146th" "147th"
     "148th" "149th" "150th" "151st" "152nd" "153rd" "154th" "155th"
     "156th" "157th" "158th" "159th" "160th" "161st" "162nd" "163rd"
     "164th" "165th" "166th" "167th" "168th" "169th" "170th" "171st"
     "172nd" "173rd" "174th" "175th" "176th" "177th" "178th" "179th"
     "180th" "181st" "182nd" "183rd" "184th" "185th" "186th" "187th"
     "188th" "189th" "190th" "191st" "192nd" "193rd" "194th" "195th"
     "196th" "197th" "198th" "199th" "200th" "201st" "202nd" "203rd"
     "204th" "205th" "206th" "207th" "208th" "209th" "210th" "211th"
     "212th" "213th" "214th" "215th" "216th" "217th" "218th" "219th"
     "220th" "221st" "222nd" "223rd" "224th" "225th")
    > 


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kent M Pitman
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <uodedjbsk.fsf@nhplace.com>
····@rpw3.org (Rob Warnock) writes:

> Don Geddis  <···@geddis.org> wrote:
> +---------------
> | So if I do   (format t "~:R" 4)
> | I get        fourth
> | but I want   4th
> | Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
> +---------------
> 
> Not using "~R" per se, but I once had occasion to need the same
> thing, and I did it something like this [though ISTR that I may
> have used an AREF on a vector of 10 strings instead of the CASE]:
> 
>     > (defun ordinal-suffix (n)
> 	(let ((n (mod n 100)))
> 	  (if (<= 11 n 13)    ; special-case English-language rule
> 	    "th"
> 	    (let ((which (mod n 10)))
> 	      (case which
> 		((1) "st")
> 		((2) "nd")
> 		((3) "rd")
> 		(t "th"))))))
> 
>     ORDINAL-SUFFIX
>     > (loop for i to 225
> 	collect (format nil "~d~a" i (ordinal-suffix i)))

Ick.  Coding things like that not only requires way too much thought
but also ends up way too efficient.  The following is easier on the
brain and not so irritatingly conservative about computational and 
garbage collection overhead...

(defun abbreviated-ordinal (n)
  (let* ((long-ordinal (format nil "~:R" n))
         (len (length long-ordinal)))
    (format nil "~D~A" n (subseq long-ordinal (- len 2) len))))

(defun show-abbreviated-ordinal (stream n at-sign colon &rest params)
  (declare (ignore at-sign colon params))
  (write-string (abbreviated-ordinal n) stream))

;; Note that ~/.../ requires a package prefix, it's NOT optional.

(format nil "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 3)
=> "3rd"

(format t "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 37)
37th
=> NIL
From: Ken Tilton
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <fXFWi.22$BT4.2@newsfe10.lga>
Kent M Pitman wrote:
> ····@rpw3.org (Rob Warnock) writes:
> 
> 
>>Don Geddis  <···@geddis.org> wrote:
>>+---------------
>>| So if I do   (format t "~:R" 4)
>>| I get        fourth
>>| but I want   4th
>>| Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
>>+---------------
>>
>>Not using "~R" per se, but I once had occasion to need the same
>>thing, and I did it something like this [though ISTR that I may
>>have used an AREF on a vector of 10 strings instead of the CASE]:
>>
>>    > (defun ordinal-suffix (n)
>>	(let ((n (mod n 100)))
>>	  (if (<= 11 n 13)    ; special-case English-language rule
>>	    "th"
>>	    (let ((which (mod n 10)))
>>	      (case which
>>		((1) "st")
>>		((2) "nd")
>>		((3) "rd")
>>		(t "th"))))))
>>
>>    ORDINAL-SUFFIX
>>    > (loop for i to 225
>>	collect (format nil "~d~a" i (ordinal-suffix i)))
> 
> 
> Ick.  Coding things like that not only requires way too much thought
> but also ends up way too efficient.  The following is easier on the
> brain and not so irritatingly conservative about computational and 
> garbage collection overhead...
> 
> (defun abbreviated-ordinal (n)
>   (let* ((long-ordinal (format nil "~:R" n))
>          (len (length long-ordinal)))
>     (format nil "~D~A" n (subseq long-ordinal (- len 2) len))))
> 
> (defun show-abbreviated-ordinal (stream n at-sign colon &rest params)
>   (declare (ignore at-sign colon params))
>   (write-string (abbreviated-ordinal n) stream))
> 
> ;; Note that ~/.../ requires a package prefix, it's NOT optional.
> 
> (format nil "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 3)
> => "3rd"
> 
> (format t "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 37)
> 37th
> => NIL
> 

Sweet. I had:

(loop for i to 10
     for j = (let ((n (mod i 100)))
               (if (<= 11 n 13)
                   4 (min (mod n 10) 4)))
     collect (format nil "~d~c~c" i
               (schar "tsnrt" j)
               (schar "htddh" j)))

kzo

-- 
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Don Geddis
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <87wst0kz2b.fsf@geddis.org>
>>>Don Geddis  <···@geddis.org> wrote:
>>>+---------------
>>>| So if I do   (format t "~:R" 4)
>>>| I get        fourth
>>>| but I want   4th
>>>| Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
>>>+---------------

>> ····@rpw3.org (Rob Warnock) writes:
>>>    (defun ordinal-suffix (n)
>>>	(let ((n (mod n 100)))
>>>	  (if (<= 11 n 13)    ; special-case English-language rule
>>>	    "th"
>>>	    (let ((which (mod n 10)))
>>>	      (case which
>>>		((1) "st")
>>>		((2) "nd")
>>>		((3) "rd")
>>>		(t "th"))))))

> Kent M Pitman wrote:
>> (defun abbreviated-ordinal (n)
>>   (let* ((long-ordinal (format nil "~:R" n))
>>          (len (length long-ordinal)))
>>     (format nil "~D~A" n (subseq long-ordinal (- len 2) len))))
>> (defun show-abbreviated-ordinal (stream n at-sign colon &rest params)
>>   (declare (ignore at-sign colon params))
>>   (write-string (abbreviated-ordinal n) stream))
>> ;; Note that ~/.../ requires a package prefix, it's NOT optional.
>> (format nil "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 3)
>> => "3rd"

Ken Tilton <···········@optonline.net> wrote on Fri, 02 Nov 2007:
> (loop for i to 10
>     for j = (let ((n (mod i 100)))
>               (if (<= 11 n 13)
>                   4 (min (mod n 10) 4)))
>     collect (format nil "~d~c~c" i
>               (schar "tsnrt" j)
>               (schar "htddh" j)))

Thanks, all!  While falling asleep last night, I sketched out Rob's solution
to myself, and (the first half of) Kent's solution.  Didn't know if there was
a simpler "obvious" way that I was missing.

Kenny's solution I would never have invented in a million years.  I am
nonetheless pleased that I am still able to at least understand such sublime
code fragments from His Kennyness.  (Kenniness?)

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
The Creation of the Universe was made possible by a grant from Texas
Instruments.  -- PBS
From: Ken Tilton
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <75RWi.546$BT4.463@newsfe10.lga>
Don Geddis wrote:
>>>>Don Geddis  <···@geddis.org> wrote:
>>>>+---------------
>>>>| So if I do   (format t "~:R" 4)
>>>>| I get        fourth
>>>>| but I want   4th
>>>>| Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
>>>>+---------------
> 
> 
>>>····@rpw3.org (Rob Warnock) writes:
>>>
>>>>   (defun ordinal-suffix (n)
>>>>	(let ((n (mod n 100)))
>>>>	  (if (<= 11 n 13)    ; special-case English-language rule
>>>>	    "th"
>>>>	    (let ((which (mod n 10)))
>>>>	      (case which
>>>>		((1) "st")
>>>>		((2) "nd")
>>>>		((3) "rd")
>>>>		(t "th"))))))
> 
> 
>>Kent M Pitman wrote:
>>
>>>(defun abbreviated-ordinal (n)
>>>  (let* ((long-ordinal (format nil "~:R" n))
>>>         (len (length long-ordinal)))
>>>    (format nil "~D~A" n (subseq long-ordinal (- len 2) len))))
>>>(defun show-abbreviated-ordinal (stream n at-sign colon &rest params)
>>>  (declare (ignore at-sign colon params))
>>>  (write-string (abbreviated-ordinal n) stream))
>>>;; Note that ~/.../ requires a package prefix, it's NOT optional.
>>>(format nil "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 3)
>>>=> "3rd"
> 
> 
> Ken Tilton <···········@optonline.net> wrote on Fri, 02 Nov 2007:
> 
>>(loop for i to 10
>>    for j = (let ((n (mod i 100)))
>>              (if (<= 11 n 13)
>>                  4 (min (mod n 10) 4)))
>>    collect (format nil "~d~c~c" i
>>              (schar "tsnrt" j)
>>              (schar "htddh" j)))

Ooof, needlessly efficient at the expense of pure functionalism and 
clarity, and we need the taoist flow PG identified as the hallmark of 
True Lisp Clode.

Better:

(symbol-macrolet ((n (mod i 100)))
   (loop for i to 10
       collect (format nil "~d~{~c~}" i
                 (loop for s in '("tsnrt" "htddh")
                     collecting (schar s (if (<= 11 n 13)
                                             4 (min (mod n 10) 4)))))))

The swoop is intended to convey The Way, The Road winding off into the 
distance.

Note that this cannot be done in F#.

> 
> 
> Thanks, all!  While falling asleep last night, I sketched out Rob's solution
> to myself, and (the first half of) Kent's solution.  Didn't know if there was
> a simpler "obvious" way that I was missing.
> 
> Kenny's solution I would never have invented in a million years.  I am
> nonetheless pleased that I am still able to at least understand such sublime
> code fragments from His Kennyness.  (Kenniness?)

That's the next Stupid Format Tricks Quiz.

kzo

-- 
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Kamen TOMOV
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <ud4usog7n.fsf@cybuild.com>
On Fri, Nov 02 2007, Kent M Pitman wrote:

> ····@rpw3.org (Rob Warnock) writes:
>
>> Don Geddis  <···@geddis.org> wrote:
>> +---------------
>> | So if I do   (format t "~:R" 4)
>> | I get        fourth
>> | but I want   4th
>> | Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
>> +---------------
>> 
>> Not using "~R" per se, but I once had occasion to need the same
>> thing, and I did it something like this [though ISTR that I may
>> have used an AREF on a vector of 10 strings instead of the CASE]:
>> 
>>     > (defun ordinal-suffix (n)
>> 	(let ((n (mod n 100)))
>> 	  (if (<= 11 n 13)    ; special-case English-language rule
>> 	    "th"
>> 	    (let ((which (mod n 10)))
>> 	      (case which
>> 		((1) "st")
>> 		((2) "nd")
>> 		((3) "rd")
>> 		(t "th"))))))
>> 
>>     ORDINAL-SUFFIX
>>     > (loop for i to 225
>> 	collect (format nil "~d~a" i (ordinal-suffix i)))
>
> Ick.  Coding things like that not only requires way too much thought
> but also ends up way too efficient.  The following is easier on the
> brain and not so irritatingly conservative about computational and 
> garbage collection overhead...
>
> (defun abbreviated-ordinal (n)
>   (let* ((long-ordinal (format nil "~:R" n))
>          (len (length long-ordinal)))
>     (format nil "~D~A" n (subseq long-ordinal (- len 2) len))))
>
> (defun show-abbreviated-ordinal (stream n at-sign colon &rest params)
>   (declare (ignore at-sign colon params))
>   (write-string (abbreviated-ordinal n) stream))

The Rob's solution might be verbose, complex and inefficient, however
it has one big advantage - it's extensible to support other languages.

As you know the multi-language support is an objective reason when
weighting one or another solution.

-- 
�����
From: Kent M Pitman
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <ulk9gfv62.fsf@nhplace.com>
Kamen TOMOV <·····@cybuild.com> writes:

> The Rob's solution might be verbose, complex and inefficient, however
> it has one big advantage - it's extensible to support other languages.

Good point.  I had actually thought of that but forgot to write in
"mine is also harder to internationalize" as one of my touted virtues. ;)

But more seriously, his paradigm certainly is... but the choice points
are all different, of course.

Also, once you start to internationalize you realize that additional
data is needed, since the choice of gender and other such information
plays in.  The choice between "6o" and "6a" in some languages, for
example.  (And some languages require even more concepts than gender
to play in, I think--aren't there languages that count differently for
objects of different classes, such as whether the thing being couned
is alive or not, no?  Japanese maybe?  I don't know any Japanese but
for some reason I have it in my head that it has such a distinction
... I took survey courses on the world languages years ago and we
covered issues like this but the details get fuzzier over time. Maybe
someone will refresh or correct my memory.)

> As you know the multi-language support is an objective reason when
> weighting one or another solution.

Certainly.  I have from time to time tried to develop tools that
accommodate that space, and I totally agree it's important.  In the
case in question, though, with the dataflow usually given (e.g.,
through format arguments), the problem is arguably theoretically
unsolvable once you go outside the "narrow" region of CL's preferred
language, Federation Standard.  One has to relax some constraint
(either more dataflow in [gender, etc], or less flexibility out [works
only in one or a small number of languages]).
From: Brian Palmer
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <0wh1wb8tepm.fsf@rescomp.stanford.edu>
Kent M Pitman <······@nhplace.com> writes:

> (And some languages require even more concepts than gender
> to play in, I think--aren't there languages that count differently for
> objects of different classes, such as whether the thing being couned
> is alive or not, no?  Japanese maybe? 

Yes. Japanese uses different "counter" suffixes depending on object
type; in addition, the numbers can change from Chinese to Japanese
numbers (e.g., ni-ban is the ordinal "two", ringo ni-ko is "two
apples", but "futa-tsu" is "two (miscellaneous things)"); the futatsu
comes from the traditional Japanese numbering system).

http://en.wikipedia.org/wiki/Japanese_counter_word goes into some of
the gory details.
-- 
I'm awfully glad I'm a Beta, because I don't work so hard.
From: Harald Hanche-Olsen
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <pco7il04k5h.fsf@shuttle.math.ntnu.no>
+ Kent M Pitman <······@nhplace.com>:

> Also, once you start to internationalize you realize that additional
> data is needed, since the choice of gender and other such
> information plays in.

Plus, in some languages, there is hardly any tradition for abbreviated
ordinals.  I'll stick my neck out and state that I have never seen
them in Norwegian, except possibly in some fairly old literature.  But
that is arguably Danish, not Norwegian anyhow.  8-)

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Kamen TOMOV
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <u1wb8nl4o.fsf@cybuild.com>
On Fri, Nov 02 2007, Kent M Pitman wrote:

> Kamen TOMOV writes:
>
>> The Rob's solution might be verbose, complex and inefficient,
>> however it has one big advantage - it's extensible to support other
>> languages.
>
> Good point.  I had actually thought of that but forgot to write in
> "mine is also harder to internationalize" as one of my touted
> virtues. ;)
>
> But more seriously, his paradigm certainly is... but the choice
> points are all different, of course.
>

Sure. 

> Also, once you start to internationalize you realize that additional
> data is needed, since the choice of gender and other such
> information plays in.

Right. Even popular languages like French and (I suppose) Spanish have
gender.

> The choice between "6o" and "6a" in some languages, for example.

Hmm what would "6o" or "6a" mean?

> (And some languages require even more concepts than gender to play
> in, I think--aren't there languages that count differently for
> objects of different classes, such as whether the thing being couned
> is alive or not, no?  Japanese maybe?  I don't know any Japanese but
> for some reason I have it in my head that it has such a distinction
> ... I took survey courses on the world languages years ago and we
> covered issues like this but the details get fuzzier over
> time. Maybe someone will refresh or correct my memory.)

At least Bulgarian and Russian qualify. For example you count:

- one male
- one female
- one thing

and in these languages the word for "one" is different for all
cases. The destinction between "male" and "female" objects is not
always obvious to foreigners studying these languages. The destiction
of "things" include all not living things as well as all animals as
well as the kids.

>> As you know the multi-language support is an objective reason when
>> weighting one or another solution.
>
> Certainly.  I have from time to time tried to develop tools that
> accommodate that space, and I totally agree it's important.  In the
> case in question, though, with the dataflow usually given (e.g.,
> through format arguments), the problem is arguably theoretically
> unsolvable once you go outside the "narrow" region of CL's preferred
> language, Federation Standard.  One has to relax some constraint
> (either more dataflow in [gender, etc], or less flexibility out [works
> only in one or a small number of languages]).

Constraint relaxation is fine - as long as there exist a reasoable
solution like in the current issue. By the way it is very interesting
to me when did multi-language support started to matter during the
development of Lisp?

Best regards,

-- 
�����
From: Kent M Pitman
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <uejf8ot9c.fsf@nhplace.com>
Kamen TOMOV <·····@cybuild.com> writes:

> Right. Even popular languages like French and (I suppose) Spanish have
> gender.
> 
> > The choice between "6o" and "6a" in some languages, for example.
> 
> Hmm what would "6o" or "6a" mean?

sixth. (i.e., sexto or sexta in Spanish or Portugues, for example.
 Note that "sexta" also means Friday in Portuguese, but as it happens,
 I believe, that can be traced back to its original meaning as "sixth"
 since I believe the full name is "sexta-feira" and it means
 "sixth fair [i.e., market] day").

I was just picking that as one of many examples of a masculine/feminine
ending problem.

Btw, in regular text, these adjectives can also be pluralized for harmony
with their associated noun, but I don't know if either language employs
abbreviations like 6os and 6as or if they stick with 6o and 6a or if they
just revert to sextos and sextas rather than get involved in that.
(Hmmm, a quick google search for 6os OR 6as in Spanish does turn up 13,600
hits, and some of them do look like they are trying to agree with a nearby
noun, so maybe that's the answer.)

It's for this reason that CL didn't make an attempt to solve this problem.
The tools we offer in the base language are in support of programmers, not
end users, really.  To the extent that CL tried to accommodate 
internationalization, it was mostly to not make decisions that stood in the
way of vendors doing what they needed to do in the way of extensions.
From: Kamen TOMOV
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <u8x5fcsui.fsf@cybuild.com>
On Sat, Nov 03 2007, Kent M Pitman wrote:

> Kamen TOMOV <·····@cybuild.com> writes:
>
>> Right. Even popular languages like French and (I suppose) Spanish have
>> gender.
>> 
>> > The choice between "6o" and "6a" in some languages, for example.
>> 
>> Hmm what would "6o" or "6a" mean?
>
> sixth. (i.e., sexto or sexta in Spanish or Portugues, for example.
> Note that "sexta" also means Friday in Portuguese, but as it
> happens, I believe, that can be traced back to its original meaning
> as "sixth" since I believe the full name is "sexta-feira" and it
> means "sixth fair [i.e., market] day").

Of course. I shouldn't post here at 4am :)

> I was just picking that as one of many examples of a
> masculine/feminine ending problem.
>
> Btw, in regular text, these adjectives can also be pluralized for
> harmony with their associated noun, but I don't know if either
> language employs abbreviations like 6os and 6as or if they stick
> with 6o and 6a or if they just revert to sextos and sextas rather
> than get involved in that.  (Hmmm, a quick google search for 6os OR
> 6as in Spanish does turn up 13,600 hits, and some of them do look
> like they are trying to agree with a nearby noun, so maybe that's
> the answer.)

Yeah, that's another good point of yours. Luckily in Bulgarian this
affects the suffix only by concenating the string "��" at the end. 

In fact that's not all the story. In Bulgarian the definite article is
not another word preceding the word in question like in English, but
it is also a suffix. Luckily that's easy in this concrette case as it
means concatenation of the character #\� at the end.

> It's for this reason that CL didn't make an attempt to solve this
> problem.  The tools we offer in the base language are in support of
> programmers, not end users, really.  To the extent that CL tried to
> accommodate internationalization, it was mostly to not make
> decisions that stood in the way of vendors doing what they needed to
> do in the way of extensions.

Here is how the international version might look like (until the long
ordinal version is implemented):

(defun ordinal-suffix (i)
  (apply #'format nil
	 #+bulgarian
	 (list "~D~Ci" i 
	       (let ((n (mod i 100)))
		 (if (= n 0) 
		     #\�
		     (if (<= 9 n 20) 
			 #\�
			 (case (mod n 10) 
			   ((1) #\�) 
			   ((2) #\�)
			   ((7) #\�)
			   ((8) #\�)
			   (t #\�))))))
	 #-nolanguagedefined
	 (list "~D~A" i
	       (let* ((long-ordinal (format nil "~:R" i))
		      (len (length long-ordinal)))
		 (subseq long-ordinal (- len 2) len)))))

I didn't see why I should use two stage algorithm (1st: calculate
index; 2nd: parse string to get a character as in Kenny did) instead
of one stage, beside the pervasivity of the loop's. By the way I
wondered could it be done with three embedded loops instead of two :-)

-- 
�����
From: Edi Weitz
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <u1wb7mf3g.fsf@agharta.de>
On 02 Nov 2007 04:23:39 -0400, Kent M Pitman <······@nhplace.com> wrote:

> ;; Note that ~/.../ requires a package prefix, it's NOT optional.

Really?  22.3.5.4 says this:

  If /name/ does not contain a ":" or "::", then the whole /name/
  string is looked up in the COMMON-LISP-USER package.

Edi.


  CL-USER 1 > *package*
  #<The COMMON-LISP-USER package, 27/32 internal, 0/4 external>

  CL-USER 2 > (defun abbreviated-ordinal (n)
                (let* ((long-ordinal (format nil "~:R" n))
                       (len (length long-ordinal)))
                  (format nil "~D~A" n (subseq long-ordinal (- len 2) len))))
  ABBREVIATED-ORDINAL

  CL-USER 3 > (defun show-abbreviated-ordinal (stream n at-sign colon &rest params)
                (declare (ignore at-sign colon params))
                (write-string (abbreviated-ordinal n) stream))
  SHOW-ABBREVIATED-ORDINAL

  CL-USER 4 > (format nil "~/CL-USER::SHOW-ABBREVIATED-ORDINAL/" 3)
  "3rd"

  CL-USER 5 > (defpackage :foo (:use :cl))
  #<The FOO package, 0/16 internal, 0/16 external>

  CL-USER 6 > (in-package :foo)
  #<The FOO package, 0/16 internal, 0/16 external>

  FOO 7 > (format nil "~/SHOW-ABBREVIATED-ORDINAL/" 3)
  "3rd"

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Kent M Pitman
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <uabpthiqy.fsf@nhplace.com>
Edi Weitz <········@agharta.de> writes:

> On 02 Nov 2007 04:23:39 -0400, Kent M Pitman <······@nhplace.com> wrote:
> 
> > ;; Note that ~/.../ requires a package prefix, it's NOT optional.
> 
> Really?  22.3.5.4 says this:
> 
>   If /name/ does not contain a ":" or "::", then the whole /name/
>   string is looked up in the COMMON-LISP-USER package.
> 
> Edi.

I can see how my remark would confuse you as to my intent, since I
didn't phrase that in a manner compatible with the wording of the
spec, but I'll just clarify by saying the spec and I are not in
serious disagreement.  (Your example is, strictly speaking, correct
for as far as it goes, and I don't dispute your reading. But there are
a great many things one can do in the world that are not illegal, yet
are ill-avised nevertheless.  Read on.)

Part of the issue is whether you consider things in CL-USER to be
"really there".  CL-USER is a very fragile, maleable package which the
user is allowed to put junk into and rearrange however he/she likes.
You are permitted to change its package inheritance, etc.  You are
dumped there as your sandbox for code that's not in any other package.

I sometimes use CL-USER as a bootstrap/foothold package when loading a
system, e.g., to hold onto default values for parameters long enough
to have them be picked up by a more durable package.  But I try not to
do any more of that than I have to, and specifically not any longer than
from the time I start loading my system to the time I stop loading it,
not because that time window is guaranteed to me, but because that's 
usually the smallest window of need that I can reasonably and usefully 
arrange.

The other part of the issue is that if I start (or anyone starts)
recommending that people use the CL-USER package as the home for
FORMAT extensions, then multiple people will do that.  Which means
that if any of them pick the same name, their extensions will clobber
one another.  So while it's within the spec's technical range of
permissibility, it violates the meta-theory that led to restrictions
on modifying the CL package (for example).  Really those same
restrictions should be followed by ANY shared package, which in the
case of this format extension, includes CL-USER.

So you're welcome to rely on things you define in that package staying
there if you like.  But I opt not to, and do not recommend it to you or
anyone.
From: Edi Weitz
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <upryp4uj3.fsf@agharta.de>
On 04 Nov 2007 15:13:09 -0500, Kent M Pitman <······@nhplace.com> wrote:

> So you're welcome to rely on things you define in that package
> staying there if you like.  But I opt not to, and do not recommend
> it to you or anyone.

I understand your point and it makes sense to me, but what was the
reason for this decision to look up unqualified FORMAT extensions in
CL-USER (instead of, say, just signalling an error)?

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Madhu
Subject: Re: FORMAT & abbreviated ordinals
Date: 
Message-ID: <m37ikiiz83.fsf@robolove.meer.net>
* ····@rpw3.org in ( BcGdnbpMXth1WLfanZ2dnUVZ_tSknZ2d @ speakeasy.net )

| Don Geddis  <···@geddis.org> wrote:
| +---------------
| | So if I do   (format t "~:R" 4)
| | I get        fourth
| | but I want   4th
| | Any of you FORMAT wizards know a simple way to print abbreviated ordinals?
| +---------------
|
|     > (defun ordinal-suffix (n)
| 	(let ((n (mod n 100)))
| 	  (if (<= 11 n 13)    ; special-case English-language rule
| 	    "th"
| 	    (let ((which (mod n 10)))
| 	      (case which
| 		((1) "st")
| 		((2) "nd")
| 		((3) "rd")
| 		(t "th"))))))

This breaks on negative numbers :)

* (ordinal-suffix -19) => "st"

This thread is a replay of the thread from July 2007 titled
	Subject: format and ordinal numbers
Here is my solution from  <···················@robolove.meer.net>
(m3lkdpyxc5.fsf @ robolove.meer.net ) 
<URL:http://groups.google.com/group/comp.lang.lisp/msg/115935cea900642b>

(defun ordinal-suffix (n)
  (write-string
   (if (<= 11 (setq n (abs (rem n 100))) 20)
                    "th"
                    (case (rem n 10)
                      (1 "st") (2 "nd") (3 "rd") (t "th")))))


[Posting to rid bugs :)]
--
Madhu