Number names?

Jarvis, Robert P. (Contingent) Jarvisb at timken.com
Fri Aug 24 19:49:19 UTC 2001


> From: Dan Ingalls [mailto:Dan at SqueakLand.org]
> 
> Does anyone have or know of, in Squeak or any other Smalltalk...
> 
> a method that if you give it
> 
> 	SmallInteger maxVal
> 
> it will respond with...
> 
> 	'one billion, seventy-three million, seven hundred 
> forty-one thousand, eight hundred twenty-three'

Sorry this isn't in change notice format but I did it up in Dolphin
Smalltalk.  Try adding the following methods (four in Number, one in
Fraction):

Number>>asSpoken
	"Answers a String containing the text for this number in American
English."

	| text subStrings groups leftOfDecimal rightOfDecimal exponent
groupText
	  groupCount groupSize result |

	groupText := #('' 'thousand' 'million' 'billion' 'trillion'
'quadrillion' 'quintillion' 'sextillion' 'septillion' 'octillion').

	self > 999999999999999999999999999999 ifTrue: [ ^'a really big
number' ].
	leftOfDecimal := ''.
	rightOfDecimal := ''.
	exponent := ''.
	result := String new.

	text := self printString.
	text last isDigit ifFalse: [ text := text leftString: text size - 1
].

	(text at: 1) = $+ ifTrue: [ result := 'positive '.  text := text
rightString: text size - 1 ].
	(text at: 1) = $- ifTrue: [ result := 'negative '.  text := text
rightString: text size - 1 ].

	subStrings := text subStrings: '.'.
	leftOfDecimal := subStrings at: 1.
	subStrings size > 1 ifTrue: [
		subStrings := (subStrings at: 2) subStrings: 'e'.
		rightOfDecimal := subStrings at: 1.
		subStrings size > 1
			ifTrue: [ exponent := subStrings at: 2 ] ].

	groupCount := leftOfDecimal size // 3.
	leftOfDecimal size \\ 3 ~= 0 ifTrue: [ groupCount := groupCount + 1
].

	groups := Array new: groupCount.
	1 to: groupCount do: [ :i |
		i = 1
			ifTrue: [
				leftOfDecimal size \\ 3 = 0
					ifTrue: [ groupSize := 3 ]
					ifFalse: [ groupSize :=
leftOfDecimal size \\ 3 ] ]
			ifFalse: [ groupSize := 3 ].
		groups at: i put: (leftOfDecimal leftString: groupSize).
		leftOfDecimal := leftOfDecimal rightString: leftOfDecimal
size - groupSize ].

	groups := groups reverse.

	groups size = 1
		ifTrue:
			[ text := (groups at: 1).
			text size = 3 ifTrue: [
				(text at: 1) ~= $0 ifTrue: [
					result := result, (self spokenDigit:
(text at: 1)), ' hundred ' ].
				text := text rightString: 2 ].
			text size = 2 ifTrue: [
				(text at: 1) ~= $0
					ifTrue: [
						(text at: 1) ~= $1
							ifTrue: [ result :=
result, (self spokenTensDigit: (text at: 1)), ' '.
								    text :=
text rightString: 1 ]
							ifFalse: [ result :=
result, (self spokenTeensDigit: (text at: 2)).
								     text :=
'' ] ]
					ifFalse: [ 
						(text at: 2) ~= $0 ifTrue: [
result := result, 'and ' ].
						text := text rightString: 1
] ].
			text size = 1 ifTrue: [
				(text at: 1) ~= $0 ifTrue: [
					result := result, (self spokenDigit:
(text at: 1)) ] ] ]
		ifFalse: [
			groups size to: 1 by: -1 do: [ :i |
				result := result, (groups at: i) asNumber
asSpoken, ' ', (groupText at: i), ' ' ] ].

	rightOfDecimal size > 0 ifTrue: [
		result := result, ' point '.
		1 to: rightOfDecimal size do: [ :i |
			result := result, (rightOfDecimal at: i) asString
asNumber asSpoken, ' ' ] ].

	exponent size > 0 ifTrue: [
		result := result, 'times ten to the ', (exponent
rightString: exponent size - 1) asString asNumber asSpoken, 'th' ].

	^result


Number>>spokenDigit: aCharacter
	| digitText |

	digitText := #('zero' 'one' 'two' 'three' 'four' 'five' 'six'
'seven' 'eight' 'nine').
	^digitText at: aCharacter asString asNumber + 1


Number>>spokenTeensDigit: aCharacter
	| digitText |

	digitText := #('ten' 'eleven' 'twelve' 'thirteen' 'fourteen'
'fifteen' 'sixteen' 'seventeen' 'eighteen' 'nineteen').
	^digitText at: aCharacter asString asNumber + 1


Number>>spokenTensDigit: aCharacter
	| digitText |

	digitText := #('' '' 'twenty' 'thirty' 'forty' 'fifty' 'sixty'
'seventy' 'eighty' 'ninety').
	^digitText at: aCharacter asString asNumber + 1


Fraction>>asSpoken
	^self numerator asSpoken, ' over ', self denominator asSpoken


This hasn't been extensively tested but seems to work OK for Integers,
Fractions, and some Floats.  Anything with an exponent comes out a bit
hokey, but at least it's something to play with.

Bob Jarvis
Compuware @ Timken




More information about the Squeak-dev mailing list